[기본 개념] 2 | (2.1) 오버라이딩, Super( )

728x90

[기본 개념] 2 | (2.1) 오버라이딩, Super( )

1> 오버라이딩이란?

2> 오버라이딩의 조건

3> 오버로딩 vs 오버라이딩

4> super

5> super( ) - 조상 클래스의 생성자

1. 오버라이딩이란?

 조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라고 한다. 자손 클래스 자신에 맞게 변경해야 하는 경우에 조상의 메서드를 오버라이딩 한다.

 

 2차원 좌표계의 한 점을 표현하기 위한 Point클래스가 있을 때, 이를 조상으로 하는 Point3D클래스, 3차원 좌표계의 한 점을 표현하기 위한 클래스를 다음과 같이 새로 작성하였다고 하자.

 

        class Point {

            int x ;

            int y ;

 

            String getLocation( ) { 

                return "x : " + x + ", y : " + y ;

            }

        }

 

        class Point3D extends Point {

            int z ;

 

            String getLocation( ) {    // 오버라이딩

                return "x : " + x + ", y : " + y + ", z : " + z ;

            }

        }

 

 이 두 클래스는 서로 상속관계에 있으므로 Point3D클래스는 Point클래스로부터 getLocation( )을 상속받지만, 상속받은 getLocation( )은 Point3D클래스에 맞지 않는다. 그래서 이 메서드를 Point3D클래스 자신에 맞게 z축의 좌표값도 포함하여 반환하도록 오버라이딩 하였다.

2. 오버라이딩의 조건

오버라이딩이 성립하기 위해서는 다음과 같은 조건을 만족해야 한다.

 

자손 클래스에서 오버라이딩하는 메서드는 조상 클래스의 메서드와

1 이름이 같아야 한다.

2 매개변수가 같아야 한다.

3 반환타입이 같아야 한다.

 

 한마디로 요약하자면 선언부가 서로 일치해야 한다는 것이다. 다만 접근 제어자와 예외는 제한된 조건 하에서만 다르게 변경할 수 있다.

 

조상 클래스의 메서드를 자손 클래스에서 오버라이딩할 때

1 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.

2 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

3 인스턴스 메서드를 static메서드로 또는 그 반대로 변경할 수 없다.

3. 오버로딩 vs 오버라이딩

오버로딩과 오버라이딩은 서로 혼동하기 쉽지만 차이는 명백하다. 오버로딩은 기존에 없는 새로운 메서드를 추가하는 것이고, 오버라이딩은 조상으로부터 상속받은 메서드의 내용을 변경하는 것이다.

 

오버로딩(overloading)     기존에 없는 새로운 메서드를 정의하는 것(new)

오버라이딩(overridiong)  상속받은 메서드의 내용을 변경하는 것(change, modify)

 

아래의 코드를 보고 오버로딩과 오버라이딩을 구별할 수 있어야 한다.

 

        class Parent {

            void parentMethod( ) { }

        }

        class Child extends Parent {

            void parentMethod( )             // 오버라이딩

            void parentMethod(int i) { }     // 오버로딩

 

            void childMethod( ) { } 

            void childMethod(int i)           // 오버로딩

            void childMethod( ) { }           // error. 중복정의 되었음.

        }

 

4. super

 super는 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는 데 사용되는 참조변수이다. 멤버변수와 지역변수의 이름이 같을 때 this를 붙여서 구별했듯이 상속받은 멤버와 자신의 멤버와 이름이 같을 때는 super를 붙여서 구별할 수 있다.

 

 super는 조상 클래스의 멤버와 자손 클래스의 멤버가 중복 정의되어 서로를 구별해야 하는 경우에만 사용하는 것이 좋다.

 

 static메서드(클래스메서드)는 인스턴스와 관련이 없다. 그래서 this와 마찬가지로 super역시 인스턴스메서드에서만 사용할 수 있다.

 

예제/SuperTest2.java

public class SuperTest2 {
    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

 

 같은 이름의 멤버변수가 조상클래스인 Parent에도 있고 자손 클래스인 Child클래스에도 있을 때는 super.x와 this.x는 서로 다른 값을 참조하게 된다. super.x는 조상클래스로부터 상속받은 멤버변수 x를 뜻하며, this.x는 자손 클래스에 선언된 멤버변수를 뜻한다.

 

이처럼 참조변수 super를 이용하여 중복정의를 서로 구별할 수 있다.

5. super( ) - 조상 클래스의 생성자

 this( )와 마찬가지로 super( ) 역시 생성자이다. this( )는 같은 클래스의 다른 생성자를 호출하는 데 사용되지만, super( )는 조상 클래스의 생성자를 호출하는데 사용된다.

 

 이 때 조상 클래스 멤버의 초기화 작업이 먼저 수행되어야 하기 때문에 자손 클래스의 생성자 첫 줄에서 조상 클래스의 생성자가 호출되어야 한다. 왜냐하면 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수도 있기 때문이다.

 

 이와 같은 조상 클래스 생성자의 호출은 클래스의 상속관계를 거슬러 올라가면서 계속 반복된다. 마지막으로 모든 클래스의 최고 조사인 Object클래스의 생성자인 Object( )까지 가서야 끝이 난다.

 

 그래서 Object클래스를 제외한 모든 클래스의 생성자는 첫 줄에 반드시 자신의 다른 생성자 또는 조상의 생성자를 호출해야 한다. 그렇지 않으면 컴파일러는 생성자의 첫 줄에 'super( ) ;'를 자동적으로 추가할 것이다.

 

예제/PointTest.java

public class PointTest {
    public static void main(String[] args) {
        Point3D p3 = new Point3D(1, 2, 3);
    }
}

class Point {
    int x, y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    String getLocation() {
        return "x : " + x + ", y : " + y;
    }
}

class Point3D extends Point {
    int z;

    Point3D(int x, int y, int z) {
        // 컴파일러가 자동으로 'super();'를 여기에 삽입한다. 이는 Point();를 의미한다.
        this.x = x;
        this.y = y;
        this.z = z;
    }

    String getLoaction() {      // 오버라이딩
        return "x : " + x + ", y : " + y + "x z : " + z;
    }
}
실행결과

java: constructor Point in class Point cannot be applied to given types;
  required: int,int
  found: no arguments
  reason: actual and formal argument lists differ in length

 

 이는 컴파일에러가 발생한다. Point3D클래스의 생성자에서 조상 클래스의 생성자인 Point( )를 찾을 수 없다는 내용이다.

 

        Point3D(int x, int y, int z) {
            super( ) ;
            this.x = x ;
            this.y = y ;
            this.z = z ;
        }

 

 이처럼 컴파일러가 자동적으로 생성자의 첫 줄에 'super( ) :'를 추가한다. super( )는 조상클래스Point의 기본 생성자인 Point( )를 뜻하므로 Point( )가 호출되는데 정의되어 있지 않기 때문에 컴파일에러가 발생한 것이다.

 

 이 에러를 수정하려면, Point클래스에 생성자 Point( )를 추가해주던가, 생성자 Point3D(int x, int y, int z)의 첫 줄에서 Point(int x, int y)를 호출하도록 변경하면 된다.

 

 

 

 

 

출처 | Java의 정석 (남궁 성)

728x90