this가 멤버변수와 지역변수의 이름이 같을 때 구별을 위해
사용한 참조변수인 것처럼 super도 변수의 구별을 위한 참조변수이다.
super는 부모 클래스에서 상속 받은 멤버와 본인 클래스의 멤버의 이름이 같을 때 부모 클래스의 멤버를 호출하기 위해 사용된다.
조상 클래스로부터 상속 받은 멤버도 자신의 멤버이므로 this를 사용할 수 있다.
그래도 상속받은 멤버와 자기 자신의 멤버가 같아서 구별을 해야할 때 사용한다.
class Main {
public static void main(String[] args) {
Child c = new Child();
c.method();
}
}
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
void method() {
System.out.println("x : " + x);
System.out.println("this.x : " + this.x);
System.out.println("super.x : " + super.x);
}
}
실행 결과 :
x : 20
this.x : 20
super.x : 10
결과를 보면 알 수 있듯이 멤버 변수의 이름이 같으면 super 키워드를 통해 상위 클래스의 멤버 변수를 호출할 수 있다.
만약 Child 클래스의 멤버 변수 x가 없다면 결과가 어떻게 될까?
x와 this.x, super.x 모두 상위 클래스인 Parent 클래스의 멤버 변수 x 를 호출!
super 키워드는 상위 클래스의 메소드도 호출할 수 있다.
부모 클래스의 메소드를 오버라이딩할 때 자주 사용한다.
class Point {
int x;
int y;
String getLocation() {
return "x :" + x + ", y :" + y;
}
}
class Point3D extends Point {
int z;
String getLocation() {
return super.getLocation() + ", z :" + z;
}
}
위의 코드처럼 오버라이딩을 할 때, 부모 클래스의 메소드에 내용을 추가하는 경우에 super 키워드를 이용할 수 있다.
this( )가 생성자인 것처럼 super( )도 생성자이다.
super( )는 조상 클래스의 생성자를 호출하는데 사용된다.
자식 클래스의 인스턴스를 생성하면, 자식의 멤버와 부모의 멤버가 모두 합쳐져서 인스턴스가 생성된다.
이 때, 부모 클래스의 멤버도 초기화가 수행되어야 하기 때문에 부모 클래스의 생성자가 호출이 된다.
자식 클래스의 인스턴스를 생성하면 상위 클래스의 생성자가 무조건 호출된다.
Object 클래스의 생성자인 Object( )까지 거슬러 올라가면서 조상 클래스의 생성자를 호출한다.
Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에 생성자인
this( ) 또는 super( )를 호출해야 한다.
그렇지 않으면 컴파일러가 자동적으로super( );를 생성자의 첫 줄에 삽입한다.
class Main {
public static void main(String[] args) {
B b = new B(3);
}
}
class A {
int i;
A(int i) {
this.i = i;
}
}
class B extends A {
int j;
B(int i, int j) {
this.i = i;
this.j = j;
}
}
위의 코드를 실행하게 되면 컴파일 에러가 발생한다.
그 이유는 B 클래스의 생성자의 첫 줄이 생성자를 호출하는 문장이 아니기 때문에 컴파일러가 자동으로 super( ); 추가하기 때문이다.
B(int i, int j) {
super();
this.i = i;
this.j = j;
}
이렇게 되면 super( )을 의미하는 A 클래스의 기본 생성자인 A( )가 호출되는데 A 클래스에는 A( )가 정의되어 있지 않기 때문에 컴파일 에러가 발생한다.
이 에러를 방지하기 위해서는
1. A 클래스에 기본 생성자인 A( )를 추가하든지
2. B 생성자에서 A 클래스에 정의되어있는 생성자(를 호출해야 한다.
B(int i, int j) {
super(i);
this.j = j;
자식 클래스에서 인스턴스를 생성했을 때,
생성자들의 호출 순서가 어떻게 되나 알아보자
class Main {
public static void main(String[] args) {
C c = new C();
}
}
class A {
int a;
A(int a) {
super(); // 없어도 컴파일러가 자동 추가
this.a = a;
}
}
class B extends A {
int b;
B(int a, int b) {
super(a);
this.b = b;
}
}
class C extends B {
int c;
C( ) {
this(10, 20, 30);
}
C(int a, int b, int c) {
super(a, b);
this.c = c;
}
}
main 메소드에서 C( ) 호출C(int a, int b, int c) 호출B(int a, int b) 호출A(int a) 호출Object( ) 호출이렇게 인스턴스가 생성되면 생성자가 물고 물어지면서 최상위 클래스인 Object의 생성자까지 모두 호출된다.