상속을 하려면 부모가 먼저 있어야지
생성자 안에서 다른 생성자를 호출하는 경우가 있다. 특히 자식 클래스가 부모 클래스를 상속받고 있다면, 자식 클래스의 객체를 생성하면서 생성자가 호출될 때 첫 줄에 부모 클래스의 생성자가 호출된다. 만약 부모 클래스의 생성자 코드 상에 생략되어 있다면, 자바 컴파일러가 알아서 생성해주고 부모 클래스의 생성자 코드가 실행된다.
이는 상속 관계에서 부모 클래스의 멤버들을 먼저 초기화해주기 위함이다.
상속 받는다는 것은 자식 입장에서 부모 클래스에 있는 멤버들을 자유롭게 갖다가 쓸 수 있어야 한다는 것이므로 부모 클래스의 멤버들을 먼저 초기화해주게 되는 것이다.
내부적인 동작으로는 자식 클래스의 객체가 생성되기 전에 부모의 객체가 먼저 생성되고 자식의 객체가 생성된다.
이러한 자식 클래스와 생성자가 있다고 해보자.
public DmbCellPhone extends CellPhone {
private String brand;
public DmbCellPhone(int number, String brand) {
super(number);
this.brand = brand;
}
}
그리고 이러한 부모 클래스가 있다고 해보자.
public CellPhone {
private int number;
public CellPhone(int number) {
this.number = number;
}
}
이때 자식 클래스의 super(number) 라는 부모 클래스의 생성자 호출을 통해 DmbCellPhone 자식 클래스에서 부모 클래스의 필드인 number의 값이 초기화될 수 있는 것이다.
상식적으로 생각해서 상속이라는 게 부모 클래스의 모든 멤버를 자식 쪽에서 쓸 수 있는 건데, 자식 클래스에는 없는 부모 클래스의 필드나 메소드를 사용할 수 있으려면 내부적으로 부모 클래스의 객체가 먼저 생성되어서 부모 클래스에만 있는 필드의 값에 초기화가 일어나고 자식 클래스의 생성자가 동작하는 것이 맞다.
그러나 생성자에서 타 생성자를 호출할 때는 반드시 첫 줄에서 하나만 호출이 가능하다
자바 컴파일러에서 super()를 무조건 만들어준대!!! 에 집중하다보면 간과하게 되는 하나의 약속이 있다.
바로 생성자에서 타 생성자를 호출할 때는 반드시 첫 줄에서 하나만 호출이 가능하다는 것이다.
자식 클래스의 생성자가 여러 개 있다면 이러한 경우가 왕왕 있다.
예를 들어 Parent 클래스를 상속받는 Child 클래스가 있다.
이때 Child 클래스의 기본 생성자에서 호출되는 생성자의 첫 줄에 이미 this("홍길동") 이라는 Child(String name) 생성자를 호출하는 코드가 있다.
package Section1;
public class Child extends Parent{
private String name;
public Child() {
this("홍길동");
System.out.println("Child() call"); // 네 번째로 프린트됨
}
public Child(String name) {
this.name = name;
System.out.println("Child(String name) call"); // 세 번째로 프린트 됨
}
}
부모 클래스는 이렇게 생겼다.
package Section1;
public class Parent {
public String nation;
public Parent() {
this("대한민국");
System.out.println("parent() call"); // 두 번째로 프린트됨
}
public Parent(String nation) {
this.nation = nation;
System.out.println("parent(String nation) call"); // 첫번째로 프린트됨
}
}
이런 경우, this("홍길동") 이전에 super() 생성자가 자바 컴파일러에 의해 작동될까? 안 될까?
소제목에도 써놓았지만,생성자에서 타 생성자를 호출할 때는 반드시 첫 줄에서 하나만 호출이 가능하여 super() 생성자는 호출되지 않는다.
super()가 동작하는 부분은 Child(String name) 생성자 안에 this.name = name 이전에 동작한다.
생성자를 첫 번째 줄에서만 단 한 번 호출하는 이유는? 한 번만 초기화 하려고!
그렇다면 생성자를 첫 번째 줄에서만 호출하게 하는 이유는 무엇일까?
그 이유는 첫 번째 줄에서 생성자를 호출해야지만 == 즉, 해당 생성자에서 다른 필드에 초기화를 하기 이전에 먼저 생성자로 초기화를 해줘야지만 초기화 하는 게 무의미해지지 않기 때문이다.
예를 들어 아래와 같은 코드가 있다고 생각해보자. (틀린 코드이다)
package Section1;
public class Child extends Parent{
private String name;
private int number;
public Child(int number, String name) { // 먼저 호출된다고 가정
this.name = name;
this.number = number;
this("홍길동");
System.out.println("Child() call");
}
public Child(String name) {
this.name = name;
System.out.println("Child(String name) call");
}
}
첫 번째 생성자가 먼저 호출되었다고 가정할 때,
만약 this(홍길동)이 첫 번째 줄에 있지 않다면 어차피 두 번째 생성자를 통해 초기화 될 name 필드의 값이 첫번째 생성자에서 set 되게 된다. 생성자가 여러 개일 시 또 초기화가 될 수 있기 때문에 먼저 생성자를 첫 번째 줄에 단 한 개 호출해야 각 필드 값이 유의미하게 set 될 수 있는 것이다.
따라서 super()이 호출되는 것도 생성자 내부의 첫번째 줄에 다른 생성자가 호출되지 않을 때 호출될 수 있는 것이다.
'JAVA' 카테고리의 다른 글
[Java] 추상클래스 vs. 인터페이스 (0) | 2023.06.21 |
---|---|
[Java] Object 클래스, 다형성 (0) | 2023.06.20 |
[Java] 오버로딩, 오버라이딩 (0) | 2023.06.19 |
[Java] 참조 변수, 메서드와 생성자 (0) | 2023.06.09 |
[Java] 클래스, 객체, 참조변수 (0) | 2023.06.08 |