수퍼클래스의 메소드 Overriding (재정의)
클래스가 자신의 수퍼클래스의 메소드와 동일한 이름, 리턴타입, 매개변수를 사용하는 인스턴스 메소드를 정의할때 이 메소드는 수퍼클래스의 메소드를 오버라이딩 한다. 클래스의 객체에 대해 이 메소드가 호출될때 , 새롭게 정의된 메소드가 호출된다.(단 super.메소드 형태로 하위에서 불릴때는 재정의(Overriding) 되었더라도 재정의되기 이전의(상위의) 메소드가 불린다.)
앞의 예제 PlaneCircle은 Circle의 메소드를 오버라이딩 하지 않았다. 이제 새로운 클래스인 Ellipse클래스를 정의한다고 하자. Area()와 circumference()가 원과 타원은 틀리므로 재정의해서 타원에 맞는것으로 해야한다.
메소드 오버라이딩은 인스턴스 메소드에 한정한다. 인스턴스 변수, 쿨래스변수, 클래스 메소드인 경우엔 서브클래스에 의해 가려질수는 있으나 오버라이딩 될수는 없다. 또한 private 메소드는 서브클래싱에 의해 상속되지 않으므로 오버라이딩 될수없다.(private method는 암시적으로 final이다.)
자바가 동적 메소드 검색을 사용안하는 경우
- 메소드가 final한정자로 선언되는 경우, 오버라이딩 될수없다, 즉 자바컴파일러는
오직하나의 메소드만이 존재한다는것을 알게 된다. Final 클래스의 모든 메소드는
암시적으로 final이며 오버라이딩 될수없다.
- 결국 final 클래스및 final, static, private인 모든 메소드는 오버라이딩이 안되며 동적메소
드 검색의 대상도 아니다. 즉 실행시간에 Inlining된다.
메소드 오버라이딩은 가리는것이 아니다.
class A {
int i=10;
int f() { return i; }
static char g() { return 'A'; }
}
class B extends A{
int i=20; //A의 i가 가려지는것이다.
int f() { return -i; } //재정의
static char g() { return 'B'; }
}
public class OverrideTest {
public static void main(String[] args) {
B b = new B();
System.out.println(b.i); System.out.println(b.f());
System.out.println(b.g()); System.out.println(B.g());
A a = (B) b; //A a = b도 가능, 광역 형변환
System.out.println(a.i); System.out.println(a.f());
System.out.println(a.g()); System.out.println(A.g());
}}
class A {
int i=1; int f() { return i; }
}
class B extends A {
int i;
int f() {
i = super.i + 1; //재정의가 안되는 인스턴스 필드이므로 ((A)this).i도 가능
//이것은 인스턴스를 대상으로 하는것이므로 재정의된 B.f()가 불린다.
//재귀함수처럼 계속 자기를 호출, StackOverFlow
//return ((A)this).f() + i;
return super.f() + i; //3, //super.f() super 이므로 무조건 상위클래스의 f()를 호출
}
}
public class OverridingTest2 {
public static void main(String[] args) {
B b = new B();
System.out.println(b.f());
}
}