먼저 위 개념을 배우기 위해서 생성자 호출 방식에 대해서 다시 한번 살펴보도록 할게요
클래스에서 extends의 개념은 is a kind의 개념입니다
독수리는 새의 한 종류인 것처럼 말입니다.
따라서 새가 없다면 독수리는 없습니다.
그렇기 때문에 독수리를 생성하기 위해서는 새가 먼저 생성되어야 합니다.
결국 모든 클래스의 최상위 클래스인 Object를 가장 먼저 생성합니다.
그러나 생각해보면 클래스를 만들 때 생성자에 Object를 호출한 적이 있나요?
아마 없을 겁니다.
그 이유는 Object는 생성자가 기본생성자만 있기 때문에
자동으로 컴파일러가 내가 만든 클래스의 인스턴스를 만들 때 Object의 기본생성자를 호출해 줍니다.
예시를 하나 만들어 보았습니다.
독수리를 생성하기 위해서 새를 호출해야 하는데 호출하지 않습니다.
자동으로 호출해주었기 때문입니다.
class Bird {
int wing;
int beak;
}
class Eagle extends Bird {
int sky;
public Eagle(int sky) {
this.sky = sky;
}
}
class New {
public static void main(String[] args) {
Eagle eagle = new Eagle(3);
System.out.println("sky: " + eagle.sky);//3
System.out.println("beak: " + eagle.beak);//0
System.out.println("wing: " + eagle.wing);//0
}
}
그렇다면 만약에 Bird에 기본생성자가 아닌 다른 생성자가 있다면
어떻게 해야할까요?
super()를 통해서 가능합니다.
위는 super()가 생략된 것입니다.
class Eagle extends Bird {
int sky;
public Eagle(int sky) {
//super(); 생략 가능
this.sky = sky;
}
}
class New {
public static void main(String[] args) {
Eagle eagle = new Eagle(3);
System.out.println("sky: " + eagle.sky);//3
System.out.println("beak: " + eagle.beak);//0
System.out.println("wing: " + eagle.wing);//0
}
}
따라서 위 예시를 보면 eagle.beek과 eagle.wing는 Bird에서 가져오게 되기 때문에 출력하면 0이 나옵니다.
미리 호출되어 Bird를 생성했다는 것을 증명해주는 결과입니다.
그렇다면 기본 생성자가 아닌 경우 호출하는 방식을 살펴보겠습니다.
class Bird {
int wing;
int beak;
Bird(int wing, int beak){
this.wing = wing;
this.beak = beak;
}
}
class Eagle extends Bird {
int sky;
public Eagle(int sky) {
super(3,4);
this.sky = sky;
}
}
class New {
public static void main(String[] args) {
Eagle eagle = new Eagle(3);
System.out.println("sky: " + eagle.sky);//3
System.out.println("beak: " + eagle.beak);//3
System.out.println("wing: " + eagle.wing);//4
}
}
위와 같이 Bird에 기본 생성자 없는 경우 혹은 기본생성자와 매개변수가 있는 생성자가 있는 경우에는 반드시 super()를 통해서 자신의 출처?를 호출해야합니다.
super는 상속하는 과정에서 같은 이름의 메서드와 인스턴스 변수를 사용할 때 이를 구분하기 위해서 사용됩니다.
상속이라는 것은 개념을 확장하는 것이고
super를 통해서도 확장이 가능합니다.
하나의 예시를 작성해보았습니다.
class Car {
int wheel =10;
int door;
Car(){
this(1,1);
}
Car(int wheel, int door) {
this.wheel = wheel;
this.door = door;
}
public void openDoor() {
System.out.println("문을 자동으로 열다");
}
}
class Truck extends Car {
int wheel = 20;
public Truck(int wheel, int door) {
super(wheel, door);
}
void printTruck(){
System.out.println("truck의 wheel: "+this.wheel);
}
void printCar(){
System.out.println("car의 wheel: "+super.wheel);
}
@Override
public void openDoor() {
super.openDoor();
System.out.println("지붕을 열 수 있다.");
}
}
class Main {
public static void main(String[] args) {
Truck truck = new Truck(2, 4);
truck.setTruckWheel(20);
truck.printTruck(); // 출력: 20
truck.printCar(); //출력 : 40
System.out.println(truck.wheel);
System.out.println();
truck.setCarWheel(30);
truck.printCar(); // 출력: 30
truck.printTruck(); // 출력 : 20
System.out.println();
System.out.println();
truck.openDoor();
}
}

Car의 openDoor 메서드 이름과 Truck의 openDoor 메서드 이름은 같습니다.
위 예시를 보면 이를 구분하고 Car의 개념을 확장하기 위해서
super.openDoor를 통해서 Car의 openDoor를 호출하고
여기에 Truck의 기능(지붕이 자동으로 열린다)을 더 추가하여 확장하고 있습니다.
또한 wheel의 인스턴스 변수가 중복되어 정의되어 있어 Car의 wheel과 Truck의 wheel를 구분하여 사용하기 위해서 super와 this를 사용합니다.