본문 바로가기

Java

(상속) 생성자 호출

훈수/저작권 관련 지적 환영합니다 - 댓글 또는 audgnssweet@naver.com

 

상속에서 부모 생성자의 호출


상속 관계에 있는 클래스들 중, 하위 클래스가 생성될 때는

자동으로 상위 클래스의 생성자가 먼저 호출되고 나서 하위 클래스의 생성자가 호출됩니다.

부모가 있어야 자식이 있을 수 있는 것과 같은 원리라고 생각하시면 됩니다.

 

위와 같은 상황에서 C를 생성하면 먼저 A, B의 생성자가 호출된 뒤에 C의 생성자가 호출됩니다.

코드로 보겠습니다.

 

class A {
    A() {
        System.out.println("A");
    }
}

class B extends A{
    B() {
        System.out.println("B");
    }
}

public class C extends B{
    C() {
        System.out.println("C");
    }

    public static void main(String[] args) {
        C c = new C();
    }
}

위의 상황에서 콘솔에 출력되는 결과는

A -> B -> C 순서가 됩니다.

실행 시 C 인스턴스를 생성하려고 할 때 C가 어떤 클래스의 하위 클래스라면 상위 클래스의 생성자를 먼저 호출합니다.

컴파일러가 자동으로 super(); 키워드를 삽입해주는 것입니다.

class A {
    A() {
        System.out.println("A");
    }
}

class B extends A{
    B() {
        super();
        System.out.println("B");
    }
}

public class C extends B{
    C() {
        super();
        System.out.println("C");
    }

    public static void main(String[] args) {
        C c = new C();
    }
}

위와 같이 말이죠.

A도 물론 Object 클래스를 상속받기 때문에 Object 클래스의 생성자를 호출하지만, 그것은 생략하도록 하겠습니다.

그리고 이런 super()를 통한 부모 생성자의 호출은 '반드시' 있어야 합니다.

 

class A {
    A() {
        System.out.println("A");
    }
}

class B extends A{
    B(int b) {
        super();
        System.out.println("B");
    }
}

public class C extends B{
    C() {   //컴파일 오류 발생
        System.out.println("C");
    }

    public static void main(String[] args) {
        C c = new C();
    }
}

위에서는 B의 디폴트 생성자가 없기 때문에,

컴파일러가 자동으로 B의 디폴트 생성자를 삽입할 수 없어 컴파일 오류가 발생하게 됩니다.

그러므로 아래와 같이 명시적으로 B의 생성자를 호출해주어야 합니다.

 

class A {
    A() {
        System.out.println("A");
    }
}

class B extends A{
    B(int b) {
        super();
        System.out.println("B");
    }
}

public class C extends B{
    C() {   //컴파일 오류 해결
        super(1);
        System.out.println("C");
    }

    public static void main(String[] args) {
        C c = new C();
    }
}

 

다음으로 super()의 제약조건에 대해서 알아보겠습니다.

super() 상위 클래스 생성자 호출은 반드시 첫 번째 줄에 와야 합니다.

첫 번째 줄에 오지 않으면 컴파일 에러가 발생합니다.

예전에 생성자에서 알아보았던 this()에서도 마찬가지였었죠?


아래에서 예시로 확인하겠습니다.

class A {
    A() {
        System.out.println("A");
    }
}

class B extends A{
    B() {
        super();
        System.out.println("B");
    }
}

public class C extends B{
    C() {   
        System.out.println("C");
        super();    //컴파일 오류 발생
    }

    public static void main(String[] args) {
        C c = new C();
    }
}

위에서 super()가 C 생성자의 첫 번째 줄에 있지 않기 때문에 컴파일 오류가 발생합니다.

 

또한 이런 경우는 어떨까요?

class A {
    A() {
        System.out.println("A");
    }
}

class B extends A{
    B() {
        super();
        System.out.println("B");
    }
}

public class C extends B{
    C() {
        super();    
        this();   //컴파일 오류 발생
        System.out.println("C");
    }
    
    C(int c) {
        System.out.println("C-2");
    }

    public static void main(String[] args) {
        C c = new C();
    }
}

super()과 this()는 전부 첫 번째 줄에 와야 한다고 했는데, 그러면 super()과 this()를 동시에 사용할 수는 없는 것일까요?

맞습니다. 동시에 사용이 불가능합니다.

왜냐하면 객체 생성 시에는 반드시 한 개의 객체가 생성되어야 하는데

super() 호출 뒤

this() 생성자 안에서 또 super()를 호출하면 여러 개의 객체가 생성될 수 있기 때문에

자바에서는 그런 방식으로 사용하는 것을 금지하고 있습니다.

 

여기까지 상속에서 생성자 호출에 대해서 알아보았습니다.

'Java' 카테고리의 다른 글

(상속) 메서드 오버라이딩과 동적 바인딩  (0) 2021.05.07
(상속) 업캐스팅과 다운캐스팅  (0) 2021.05.07
(상속) 부모 클래스 접근  (0) 2021.05.07
자바 상속 기본  (0) 2021.05.07
Java static / non-static  (0) 2021.05.06