본문 바로가기
Study/JAVA

[Java] 7-2. 오버라이딩(overriding)

by jeongwle 2022. 9. 3.
728x90
반응형

 

오버라이딩(overriding)

1. 오버라이딩이란?

상위 클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라고 한다. 상속받은 메서드를 그대로 사용하기도 하지만 하위 클래스에서 다르게 변경하는 경우가 많다. 그러할 때 메서드를 오버라이딩한다.

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클래스의 인스턴스는 getLocation 메서드를 호출할 경우 z축의 좌표값도 포함된 즉 오버라이딩된 getLocation 메서드가 호출된다. 

 

2. 오버라이딩의 조건

오버라이딩은 메서드의 내용만 새로 작성하는 것이다. 메서드의 선언부는 상위 클래스의 것과 완전히 일치해야 한다. 오버라이딩이 성립하기 위한 조건을 살펴보자.

하위 클래스에서 오버라이딩하는 메서드는 상위 클래스의 메서드와
1. 이름이 같아야 한다.
2. 매개변수가 같아야 한다.
3. 반환타입이 같아야 한다.​

* 참고 : JDK1.5부터 공변 반환타입(covariant return type)이 추가되어 반환타입을 하위 클래스의 타입으로 변경하는 것은 가능하도록 조건이 완화되었다.

즉 선언부가 서로 일치해야 한다. 다만 접근 제어자(access modifier)와 예외(exception)는 제한된 조건 하에서만 다르게 변경할 수 있다.

1. 접근 제어자는 상위 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
만일 상위 클래스에 정의된 메서드의 접근 제어자가 protecrted라면, 이를 오버라이딩하는 하위 클래스의 메서드는 protected 또는 public이어야 한다. 보통은 같은 범위의 접근 제어자를 사용한다.

2. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
여기서 주의해야할 점은 단순히 선언된 예외의 개수의 문제가 아니라는 것이다. 밑의 예시를 보면 Exception은 모든 예외의 최고 상위이므로 가장 많은 개수의 예외를 던질 수 있다. 때문에 잘못된 오버라이딩이다.

class Parent {
  void parentMethod() throws IOException, SQLException {
    ...
  }
}

class Child extends Parent {
  void parentMethod() throws Exception {
   ...
  }
}​

상위 클래스의 메서드를 하위 클래스에서 오버라이딩 할 때
1. 접근 제어자를 상위 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
2. 예외는 상위 클래스의 메서드보다 많이 선언할 수 없다.
3. 인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없다.​

 

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

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

오버로딩(overloading) 기존에 없는 새로운 메서드를 정의하는 것
오버라이딩(overriding) 상속받은 메서드의 내용을 변경하는 것​

 

4. super

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

public class SuperTest {
    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);			// 20
        System.out.println("this.x = " + this.x);	// 20
        System.out.println("super.x = " + super.x);	// 10
    }
}​

상위 클래스의 메서드 역시 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를 사용해 상위 클래스의 메서드를 포함시키는 것이 좋다. 나중에 상위 클래스의 메서드가 변경되더라도 변경된 내용이 하위 클래스의 메서드에 자동으로 반영될 것이기 때문이다.

 

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

this()와 마찬가지로 super() 역시 생성자이다. this()는 같은 클래스의 다른 생성자를 호출하지만 super()는 상위 클래스의 생성자를 호출한다. 하위 클래스의 인스턴스를 생성하면 상위 클래스의 멤버와 하위 클래스의 멤버 모두 초기화 작업이 수행되어야 한다. 그래서 하위 클래스의 생성자에서 상위 클래스의 생성자가 호출되어야 한다.

생성자의 첫 줄에서 상위 클래스의 생성자를 먼저 호출해야 한다. 하위 클래스의 멤버가 상위 클래스의 멤버를 사용할 수 있기 때문이다. 그렇지 않으면 컴파일러가 자동으로 super();를 생성자의 첫줄에 삽입한다. 하지만 상위 클래스에 기본 생성자가 정의되어 있지 않은 경우 자동으로 super(); 가 삽입된다 하더라도 컴파일 에러가 난다. 이때는 상위 클래스에 기본 생성자를 추가하거나 하위 클래스의 생성자에서 상위 클래스의 다른 생성자를 호출하면 된다.
728x90
반응형

'Study > JAVA' 카테고리의 다른 글

[Java] 7-4. 제어자(modifier)  (0) 2022.09.05
[Java] 7-3. package와 import  (0) 2022.09.05
[Java] 7-1. 상속(inheritance)  (0) 2022.09.03
[Java] 6-5, 6. 생성자 & 변수의 초기화  (0) 2022.09.02
[Java] 6-4. 오버로딩(overloading)  (0) 2022.09.02

댓글