맨날 헷갈리는 Super()와 super 완-벽 이해
자식 클래스는 부모클래스를 상속받았기 때문에 자유롭게 부모의 모든 프로퍼티를 사용할 수 있다. 하지만 그럼에도 자식과 부모사이의 구분이 있어야한다. 자식클래스가 부모클래스의 프로퍼티와 동일한 이름을 갖고 있다면 그것을 부모로부터 구분해 낼 수 있어야한다는 것이다.
// 예제 1
class Object{
int a;
}
class A extends Object{
int a;
}
public static void main(String args[]){
A ins = new A();
ins.a=2 // 여기서 a는 A의 a. 즉, 자식의 변수이다
// 만약 자식에게 a라는 변수가 없었다면 부모의 a를 가리켰을 것이다.
// 여기서 자식 a가 아닌 부모의 a로 접근하고 싶다면?
ins.super.a = 20; // 이렇게 super라는 참조 변수를 사용해서 부모의 a에 접근할 수 있다
}
// 위와 같은 이유로 자바에서는 다중 상속이 불가능하다 (상속의 모호성)
//예제2
class Parent {
int a = 10;
}
class Child extends Parent {
int a = 20;
void display() {
System.out.println(a);
System.out.println(this.a);
System.out.println(super.a);
}
}
public class Inheritance03 {
public static void main(String[] args) {
Child ch = new Child();
ch.display();
}
}
자식클래스가 인스턴스를 생성하면, 인스턴스 안에는 자식 클래스의 고유 멤버 뿐만 아니라 부모 클래스의 모든 멤버까지 포함되어있다.
하지만 상속에서의 생성자는 상속되지 않는 유일한 멤버함수이다. 따라서 부모클래스의 멤버를 초기화하기 위해선, 당연히 부모클래스의 생성자를 호출해야할 것이다. 즉, 자식클래스 생성자를 호출할 때 부모클래스 생성자도 동시에 호출해야함. (정확히 말하면 부모 생성자가 먼저 실행됨)
그렇다면 자식 클래스 생성자 호출 할 때 super()를 같이 쓰면 되는구나! 라고 생각하게 됨. 하지만 이는 자바 컴파일러가 자동으로 super() 메소드를 추가해줌
그럼 여기서 의문점이 생길 것이다. 컴파일러가 알아서 부모 생성자를 호출해주는 메소드 super()를 추가해주는데(자동호출이니까 생략이 가능), 그럼 super() 메소드를 언제 쓰는 걸까?
컴파일러가 항상 super()를 자동 추가해주는 것은 아니다. 아래 예제처럼 부모클래스에 기본 생성자가 아닌 매개변수를 가지는 생성자가 있다면(=부모클래스에서 생성자가 오버로딩되면) 자동으로 추가되지 않음 (=묵시적 제공을 하지 않음)
class Parent{
int a;
Parent(int n){a=n;};
}
아! 그럼 이 때 자식클래스 생성자 호출할 때 super()를 활용하면 되겠구나!
class Parent{
int a;
Parent(int n){a=n;};
}
class Child extends Parent(){
int b;
Child(){
super()
b=20;
}
}
// 이게 오류라면 super(20) 했을 땐 어떻게 될까? 나중에 되는지 test해보자
// 기본생성자도 없고 매개변수가 있는 생성자도 없으면? 나중에 되는지 test
❌ 놉. 위의 코드는 오류가 발생함
왜냐하면 부모클래스 자체에 기본 생성자가 추가되지 않았기 때문임. 기본생성자를 호출할 때 부모클래스의 생성자에 기본생성자가 없으면 에러가 남.
어떻게 해야할까? 일단 2가지 방법이 있다.
1. 부모클래스에 기본 생성자 선언 (명시된 문제 그대로의 해결)
class Parent{
int a;
Parent(){a=10;};
Parent(int n){a=n;};
}
class Child extends Parent(){
int b;
Child(){
super();
b=20;
}
}
2. 오버로딩된 생성자에 맞춰 super()의 인자를 맞춰줌 (합리적 해결👍🏻)
class Parent{
int a;
Parent(int n){a=n;};
}
class Child extends Parent(){
int b;
Child(){
super(40);
b=20;
}
}
2번이 더 합리적인 해결방법같다!
감사합니다.