[Java] super - 생성자

코드 속의 "진돌"·2024년 3월 10일
0
post-thumbnail

✅ super - 생성자


상속 관계의 인스턴스를 생성하면 결국 메모리 내부에는 자식과 부모 클래스가 각각 다 만들어진다. Child를 만들면 부모인 Parent까지 함께 만들어지는 것이다. 따라서 각각의 생성자도 모두 호출되어야 한다.

상속 관계를 사용하면 자식 클래스의 생성자에서 부모 클래스의 생성자를 반드시 호출해야 한다.



✏️ ClassA

package extends1.super2;

public class ClassA {

  public ClassA() {
    System.out.println("ClassA 생성자");
  }
}
  • ClassA는 최상위 부모 클래스이다.



✏️ ClassB

package extends1.super2;

public class ClassB extends ClassA {

  public ClassB(int a) {
    super();  // 기본 생성자 생략 가능
    System.out.println("ClassB 생성자 a = " + a);
  }

  public ClassB(int a, int b) {
    super();  // 기본 생성자 생략 가능
    System.out.println("ClassB 생성자 a = " + a + " b = " + b);
  }
}
  • ClassBClassA를 상속 받았다. 상속을 받으면 생성자의 첫 줄에 super(...)를 사용해서 부모 클래스의 생성자를 호출해야 한다.

    예외

    생성자 첫 줄에 this(...)를 사용할 수 있다. 하지만 super(...)는 자식의 생성자 안에서 언젠가는 반드시 호출해야 한다.

  • 부모 클래스의 생성자가 기본 생성자(파라미터가 없는 생성자)인 경우에는 super()를 생략할 수 있다.
    • 상속 관계에서 첫 줄에 super(...)를 생략하면 자바는 부모의 기본 생성자를 호출하는 super()를 자동으로 만들어준다.



✏️ ClassC

package extends1.super2;

public class ClassC extends ClassB {

  public ClassC() {
    super(10, 20);
    System.out.println("ClassC 생성자");
  }
}
  • ClassCClassB를 상속 받았다. ClassB에는 다음 두 생성자가 있다.
    • ClassB(int a)
    • ClassB(int a, int b)
  • 생성자는 하나만 호출할 수 있다. 두 생성자 중에 하나를 선택하면 된다.
    • super(10, 20)를 통해 부모 클래스의 ClassB(int a, int b) 생성자를 선택했다.
  • 참고로 ClassC의 부모인 ClassB에는 기본 생성자가 없다. 따라서 부모의 기본 생성자를 호출하는 super()를 사용하거나 생략할 수 없다.



✏️ Super2Main

package extends1.super2;

public class Super2Main {

  public static void main(String[] args) {
    ClassC classC = new ClassC();
  }
}



🖥️ 실행 결과

실행해보면 ClassAClassBClassC 순서로 실행된다. 생성자의 실행 순서가 결과적으로 최상위 부모부터 실행되어서 하나씩 아래로 내려오는 것이다. 따라서 초기화는 최상위 부모부터 이루어진다. 왜냐하면 자식 생성자의 첫 줄에서 부모의 생성자를 호출해야 하기 때문이다.



⚙️ 생성자 호출 과정

1 ~ 3 과정

new ClassC()를 통해 ClassC 인스턴스를 생성한다. 이때 ClassC()의 생성자가 먼저 호출되는 것이 맞다. 하지만 ClassC()의 생성자는 가장 먼저 super(...)를 통해 ClassB(...)의 생성자를 호출한다. ClassB()의 생성자도 부모인 ClassA()의 생성자를 가장 먼저 호출한다.


4 ~ 6 과정

  • ClassA()의 생성자는 최상위 부모이다. 생성자 코드를 실행하면서 “ClassA 생성자”를 출력한다.
  • ClassA() 생성자 호출이 끝나면 ClassA()를 호출한 ClassB(...) 생성자로 제어권이 돌아간다.
  • ClassB(...) 생성자가 코드를 실행하면서 “ClassB 생성자 a=10 b=20”을 출력한다. 생성자 호출이 끝나면 ClassB(...)를 호출한 ClassC() 생성자로 제어권이 돌아간다.
  • ClassC()가 마지막으로 생성자 코드를 실행하면서 “ClassC 생성자”를 출력한다.



📚 정리

  • 상속 관계의 생성자 호출은 결과적으로 부모에서 자식 순서로 실행된다. 따라서 부모의 데이터를 먼저 초기화하고 그 다음에 자식의 데이터를 초기화한다.
  • 상속 관계에서 자식 클래스의 생성자 첫 줄에 반드시 super(...)를 호출해야 한다. 단 기본 생성자(super())인 경우 생략할 수 있다.




✅ this()와 함께 사용


코드 첫 줄에 this(...)를 사용하더라도 반드시 한번은 super(...)를 호출해야 한다.

✏️ ClassB - 코드 변경

package extends1.super2;

public class ClassB extends ClassA {

  public ClassB(int a) {
    this(a, 0);
    System.out.println("ClassB 생성자 a = " + a);
  }

  public ClassB(int a, int b) {
    super();  // 기본 생성자 생략 가능
    System.out.println("ClassB 생성자 a = " + a + " b = " + b);
  }
}



✏️ Super2Main - 코드 변경

package extends1.super2;

public class Super2Main {

  public static void main(String[] args) {
    // ClassC classC = new ClassC();

    ClassB classB = new ClassB(100);
  }
}



🖥️ 실행 결과

profile
매일 성장하는 주니어 개발자의 기록📝

0개의 댓글