[Java 상속] 상속에서의 메소드 스코프 결정 완벽 가이드
Java의 상속 관계에서 메소드 호출 범위를 단계별로 설명하는 기술 문서입니다. 아래 그림을 보고 완벽히 해석을 할 수 있도록 스코프 결정 과정을 살펴보겠다!
Parent pc = new Child(); 일때 아래 주석처럼 m1(); 은 Child의 m1() 이 실행. 왜일까?
아래 그림은 왜 이렇게 test 코드가 동작할까?
메소드 스코프 결정 과정
기본 원칙
메소드 호출 가능 여부는 다음 3단계로 확인합니다:
Parent pc = new Child();
일 때
- 앞에것을 먼저 확인(=참조 변수 타입 확인): Parent 확인
- 뒤에것을 먼저 확인(=실제 객체 타입 확인): Child 확인
- 마지막으로 오버라이딩 확인(=오버라이딩 여부 확인): 오버라이딩 된 메소드 사용하는지 확인
단계별 확인 프로세스
public class A {
void a() { System.out.println("A-a()"); }
}
class B extends A {
void a(int i) { System.out.println("B-a(int i)"); }
void b() { System.out.println("B-b()"); }
}
class C extends B {
void a() { System.out.println("C-a()"); }
void c() { System.out.println("C-c()"); }
}
class D extends C {
void a(int i) { System.out.println("D-a(int i)"); }
void b() { System.out.println("D-b()"); }
void d() { System.out.println("D-d()"); }
}
💡 메소드 호출 분석: A a = new C();
일 때
-
앞에것을 먼저 확인: A a를 확인
중요: 만약 B b 였으면 B부터 A까지 다 확인(상속관계라서!)
public class A { void a() { System.out.println("A-a()"); } }
-
뒤에것을 확인: new C()를 확인 -> 상속관계 다 확인!!
public class A { void a() { System.out.println("A-a()"); } } class B extends A { void a(int i) { System.out.println("B-a(int i)"); } void b() { System.out.println("B-b()"); } } class C extends B { void a() { System.out.println("C-a()"); } void c() { System.out.println("C-c()"); } }
-
오버라이딩 확인 후 결과 도출 (2번에서 확인한 범위에서 체크!!)
a.a();
를 구할 경우 1번 범위에 있고, 3번 오버라이딩 확인시 C클래스에 있어서 C-a() 도출a.c();
의 경우 1번 범위에 없어서 3번 오버라이딩 확인할 필요도 없이 불가a.a(5);
의 경우 1번 범위에 없어서 3번 오버라이딩 확인할 필요도 없이 불가
적용해보기
처음 소개한 그림속의 예시를 전부 이해해보자.
A a = new B();
-
a.a(); // A-a()
:- 1번 앞에것 확인했을 때 class A 에 a()가 있고,
- 3번 오버라이딩은 class B에 없으니 class A의 a() 호출!
-
a.a(3); // error
:- 1번 앞에것 확인했을 때 class A 에 a(int i)가 없다. 오버라이딩 볼 필요없이 error 출력!
B b = new C();
-
b.a(); // C-a()
:- 1번 앞에것 확인했을 때 class A~B 체크하니 class A에 a()가 있고,
- 3번 오버라이딩은 class A~C 체크하니 class C에 있어서 class C의 a() 호출!
-
b.a(5); // B-a(int i)
:- 1번 앞에것 확인했을 때 class A~B 체크하니 class B에 a(int i)가 있고,
- 3번 오버라이딩은 class A~C 체크하니 없다. class B의 a(int i) 그대로 호출!
A a = new C(); 부분은 단계별 확인 프로세스 파트에서 이미 소개했으니 PASS
B b = new D();
-
b.a(); // C-a()
:- 1번 앞에것 확인했을 때 class A~B 체크하니 class A에 a()가 있고,
- 3번 오버라이딩은 class A~D 체크하니 class C에 있어서 class C의 a() 호출!
-
b.a(5); // D-a(int i)
:- 1번 앞에것 확인했을 때 class A~B 체크하니 class B에 a(int i)가 있고,
- 3번 오버라이딩은 class A~D 체크하니 class D에 있어서 class D의 a(int i) 호출!
-
b.b(); // D-b()
:- 1번 앞에것 확인했을 때 class A~B 체크하니 class B에 b()가 있고,
- 3번 오버라이딩은 class A~D 체크하니 class D에 있어서 class D의 b() 호출!
상속 관계에서 메소드 호출 시에는 참조 변수의 타입과 실제 객체의 타입, 그리고 오버라이딩 여부를 순차적으로 확인해야 합니다.
댓글남기기