본문으로 바로가기

super와super()

category Java언어 2018. 8. 21. 18:52

이 글을 읽기전에 this키워드 글을 먼저 읽고 오는것을 권장한다.


 

 

super키워드는 두가지로 사용된다.

 

1. 자신이 상속받은 부모를 가르키는 레퍼런스 변수

 

2. 자신이 상속받은 부모의 생성자를 호출하는 생성자 함수


 

 

1. 자신이 상속받은 부모를 가르키는 레퍼런스 변수 super

 

1)용도

 

자식은 부모의 프로퍼티(필드,메소드,생성자)를 상속받기 때문에 부모의 모든 프로퍼티를 사용할 수 있다. 하지만 만약 부모의 프로퍼티와 같은 이름의 프로퍼티를 자식이 가지고 있을 경우 이를 구분할 필요가 있다. 즉, 부모와 자식이 가지고 있는 같은이름의 필드명과 오버라이딩된메소드를 구분하기 위해 사용된다.


class Ovject{

 

int a;

 

public String toString(){

getClass().getName() + '@' + Integer.toHexString(hashCode());

}

}

 

 

class A extends Object(){        //toString메소드를 만들지 않아도 사용가능한 이유?

모든 클래스는 Objet를 상속받고 있기 때문에

int a;

 

@Overridding

public String toString(A this){    //항상 자신의 메소드를 부를때 첫번째 매개변수로 자신이 넘어간다. 중요

System.out.println(this.a);

 

}

 

}

 

public static void main(String args[]){

 

A ins = new A();

 

ins.a = 10;    //이 a는 어떤 a인가?

//만약 자식에 a가 없었다면 a는 부모의a를 가르킬것이다. 하지만 자식에도 같은이름의 a가 있기때문에 이경우에는

//자식의 a를 가르킨다.

//그렇다면 부모의 a에는 어떻게 접근할 것 인가?

 

ins.super.a = 20;    //부모의 a에 접근하였다.

 

 

}


이 경우 A클래스는 Object클래스를 상속받았기 때문에 부모의 field와 method를 사용할 수 있다. 그런데 문제가 있다. 부모의 field 이름도 'a'이고 자식의 instance field 이름도 'a'이다. 그리고 부모의 메소드 이름도 'toString()'이고 A클래스의 메소드 이름도 'toString()'이다. 그렇다면 어떻게 이둘을 구분할 것인가? 이떄사용되는 것이 super참조변수 이다.

이러한 이유때문에 Java에서는 다중상속이 불가능하다(모호성 발생)


 

 

2. 자신이 상속받은 부모의 생성자를 호출하는 생성자 메소드 super()

 

1)용도

 

자식은 부모의 모든 프로퍼티에 접근할 수 있다. 그렇다면 생성자의 주된 목적인 초기화의 경우 자식의 생성자로도 충분히 상속받은 부모의 필드를 초기화 할 수 있을것이다. 그런데 왜 부모의 생성자를 호출하는 super()가 필요할까?

바로 아무리 상속을 받았다지만 자식조차 접근할 수 없는 private field의 경우는 자식의 생성자로는 초기화할 수 없기 때문이다.

 

또한 위의 참조변수super의 예시코드처럼 부모와 자식이 같은 필드명을 가졌을 경우에도 super()로 간단히 구분하여 초기화가 가능하다. 물론 참조변수super를 통해 구분하여 자식에서 초기화할 수도 있겠지만 이보단 super()를 호출하는 편이 간편하다.

 

 

 

2) super()의 동작                                         <-  출처 :   http://tcpschool.com/java/java_inheritance_super

 

동작 : A로간 후 B로가서 동작후 A로 돌아와 A를 실행  <-  A extends B

 

자식 클래스의 인스턴스를 생성하면, 해당 인스턴스에는 자식 클래스의 멤버뿐만 아니라 부모 클래스의 모든 멤버까지도 포함되어 있다.

따라서 부모 클래스의 멤버를 초기화하기 위해서는 자식 클래스의 생성자에서 부모 클래스의 생성자까지 호출해야만 한다.

이러한 부모 클래스의 생성자 호출은 모든 클래스의 부모 클래스인 Object 클래스의 생성자까지 계속 거슬러 올라가며 수행된다.

*모든클래스는 object클래스를 상속받고 있음.  extends Object 생략되어 있음.

 

따라서 Java compiler는 부모 클래스의 생성자를 명시적으로 호출하지 않는 모든 자식 클래스의 생성자 첫 줄에 자동으로 super()을 추가하여, 부모 클래스의 멤버를 초기화할 수 있도록 해준다.

*super호출을 명시적으로 사용하는 경우?
부모클래스의 생성자의 패러미터값에 변경을 주고 싶을경우

 

하지만 Java compiler는 컴파일 시 클래스에 생성자가 하나도 정의되어 있지 않아야만, 자동으로 기본 생성자를 추가해 준다.

만약 다음 예제처럼 부모 클래스에 매개변수를 가지는 생성자를 하나라도 선언했다면, 부모 클래스에는 기본 생성자가 자동으로 추가되지 않을 것이다. 따라서 다음 예제처럼 Parent 클래스를 상속받은 자식 클래스에서 super() 메소드를 사용하여 부모 클래스의 기본 생성자를 호출하게 되면, 오류가 발생하게 될 것이다.


class Parent {

    int a;

    Parent(int n) { a = n; }

}

 

class Child extends Parent {

    int b;

    Child() {

        super();

        b = 20;

    }


왜냐하면 부모 클래스인 Parent 클래스에는 기본 생성자가 추가되어 있지 않기 때문이다.

따라서 매개변수를 가지는 생성자를 선언해야 할 경우에는 되도록이면 다음 예제처럼 기본 생성자까지 명시적으로 선언하는 것이 좋다.

 

 

 

*main()메소드에서 super키워드사용은 불가능 하다.