일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 스프링 입문(무료)
- 자바 고급2편 - io
- @Aspect
- 자바 중급2편 - 컬렉션 프레임워크
- 스프링 mvc1 - 스프링 mvc
- 자바 기초
- 데이터 접근 기술
- 자바의 정석 기초편 ch2
- 자바 고급2편 - 네트워크 프로그램
- 자바의 정석 기초편 ch11
- 스프링 mvc2 - 타임리프
- 스프링 mvc2 - 검증
- 스프링 트랜잭션
- 자바의 정석 기초편 ch5
- 자바로 키오스크 만들기
- 자바로 계산기 만들기
- 2024 정보처리기사 수제비 실기
- 스프링 mvc2 - 로그인 처리
- 람다
- 자바의 정석 기초편 ch1
- 자바 중급1편 - 날짜와 시간
- 자바의 정석 기초편 ch7
- 자바의 정석 기초편 ch12
- 자바의 정석 기초편 ch14
- 2024 정보처리기사 시나공 필기
- 스프링 고급 - 스프링 aop
- 자바의 정석 기초편 ch13
- 자바의 정석 기초편 ch9
- 자바의 정석 기초편 ch6
- 자바의 정석 기초편 ch4
- Today
- Total
개발공부기록
다형성, 다형성 시작, 다형성과 캐스팅, 캐스팅의 종류, 다운캐스팅과 주의점, instanceof, 다형성과 메서드 오버라이딩 본문
다형성, 다형성 시작, 다형성과 캐스팅, 캐스팅의 종류, 다운캐스팅과 주의점, instanceof, 다형성과 메서드 오버라이딩
소소한나구리 2025. 1. 12. 21:04
1. 다형성 시작
1) 다형성
(1) 설명
- 객체지향 프로그래밍의 대표적인 특징으로는 캡슐화, 상속, 다형성이 있는데 그 중에서 다형성을 객체지향 프로그래밍의 꽃이라 불림
- 캡슐화나 상속은 직관적으로 이해하기가 쉬운 반면에 다형성은 제대로 이해하는 것과 활용하는 것이 어려운데 좋은 개발자가 되기 위해서는 다형성에 대한 이해가 필수임
- 다형성(Polymorphism)은 이름 그대로 다양한 형태, 여러 형태를 뜻하는데 프로그래밍에서는 한 객체가 여러 타입의 객체로 취급될 수 있는 능력을 뜻함
- 보통 하나의 객체는 하나의 타입으로 고정되어 있는데 다형성을 사용하면 하나의 객체가 다른 타입으로 사용될 수 있다는 의미임
- 다형성을 이해하기 위해서는 크게 다형적 참조, 메서드 오버라이딩 2가지 핵심 이론을 알아야 함
2) 다형적 참조
(1) Parent
package poly.basic;
public class Parent {
public void parentMethod() {
System.out.println("Parent.parentMethod");
}
}
(2) Child
package poly.basic;
public class Child extends Parent {
public void childMethod() {
System.out.println("Child.childMethod");
}
}
(3) PolyMain
- 부모 타입 변수로 부모 인스턴스를 참조, 자식 타입 변수로 자식 인스턴스를 참조, 부모 타입 변수로 자식 인스턴스를 참조하는 코드를 작성
- 자식 타입 변수로 부모 인스턴스를 참조하는 코드는 컴파일 오류가 발생함
- 부모 타입 변수로 자식의 기능은 호출할 수 없음
package poly.basic;
public class PolyMain {
public static void main(String[] args) {
// 부모 변수가 부모 인스턴스 참조
System.out.println("Parent -> Parent");
Parent parent = new Parent();
parent.parentMethod();
// 자식 변수가 자식 인스턴스 참조
System.out.println("Child -> Child");
Child child = new Child();
child.parentMethod();
child.childMethod();
// 부모 변수가 자식 인스턴스 참조
System.out.println("Parent -> Child");
Parent poly = new Child();
poly.parentMethod();
// Child child1 = new Parent(); // 컴파일 오류, 자식은 부모를 담을 수 없음
// 부모 타입 변수로 자식의 기능은 호출할 수 없음, 컴파일 오류 발생
// poly.childMethod(); // 호출 불가
}
}
/* 실행 결과
Parent -> Parent
Parent.parentMethod
Child -> Child
Parent.parentMethod
Child.childMethod
Parent -> Child
Parent.parentMethod
*/
(4) 부모 타입의 변수가 부모 인스턴스 참조
- Parent parent = new Parent()로 부모 타입인 Parent로 Parent 인스턴스를 생성했으므로 메모리 상에 Parent만 생성되며 자식은 생성되지 않음
- 생성된 참조값을 Parent 타입의 변수인 parent에 담아두었으므로 parent.parentMethod()로 호출하면 Parent 클래스의 parentMethod()메서드가 호출됨
(5) 자식 타입의 변수가 자식 인스턴스 참조
- Child child = new Child()로 자식 타입인 Child로 Child 인스턴스를 생성했기 때문에 메모리 상에 Child와 Parent가 모두 생성됨
- 생성된 참조값을 Child 타입의 변수인 child에 담아두고 child.childMethod()를 호출하면 인스턴스의 Child 클래스에 있는 childMethod()가 호출됨
(6-1) 다형적 참조: 부모 타입의 변수가 자식 인스턴스 참조
- Parent poly = new Child()로 부모 타입인 Parent로 Child 인스턴스를 만들었음
- 이 경우에도 자식 타입인 Child를 생성했기 때문에 메모리 상에 Child와 Parent가 모두 생성되며 생성된 참조값을 Parent 타입의 변수인 poly에 담아둠
- 자바에서 부모 타입은 자식 타입을 담을 수 있어서 이런 방식이 허용되지만 반대로 자식 타입은 부모 타입을 담을 수 없어서 Child child1 = new Parent()는 컴파일 오류가 발생함
(6-2) 다형적 참조
- 지금까지 학습한 내용을 떠올려 보면 항상 같은 타입에 참조를 대입하여 한 가지 형태만 참조할 수 있었음
- 그러나 Parent 타입의 변수는 자신인 Parent는 물론이고 자식 타입까지 참조할 수 있으며 만약 손자까지 있다면 그 손자도, 그 하위 타입도 모두 참조할 수 있음
- 즉, 자바에서 부모 타입은 자신은 물론 자신을 기준으로 모든 자식 타입을 참조할 수 있는데 이것이 바로 다양한 형태를 참조할 수 있다고하여 다형적 참조라함
(6-3) 다형적 참조와 인스턴스 실행
- poly.parentMethod()를 호출하면 먼저 참조값을 사용하여 인스턴스를 찾고 인스턴스 안에서 실행할 타입도 찾음
- poly는 Parent 타입이므로 Parent 클래스부터 시작하여 필요한 기능을 찾고 Parent 클래스에 parentMethod()가 있으므로 해당 메서드가 호출됨
(6-4) 다형적 참조의 한계
- Parent poly = new Child()로 자식을 참조한 상황에서 poly가 자식 타입인 Child에 있는 childMethod()를 호출할 수 없음
- poly.childMethod()를 실행하면 먼저 참조값을 통해 인스턴스를 찾고 인스턴스안에서 실행할 타입을 찾는데 poly는 Parent 타입이므로 Parent 클래스 부터 시작해서 필요한 기능을 찾음
- 그러나 상속 관계는 부모 방향으로 찾아 올라갈 수는 있지만 부모는 자식의 정보가 하나도 없으므로 자식 방향으로 찾아 내려갈 수는 없음
- Parent는 부모 타입이고 상위에는 부모가 없으므로(실제로는 최고조상인 Object가 있음) childMethod()를 찾을 수 없기 때문에 컴파일 오류가 발생함
- 이런 경우 childMethod()를 호출하고 싶다면 캐스팅을 통해 해결할 수 있음
- 다형적 참조의 핵심은 부모는 자식을 품을 수 있다라는 것!
- 그런데 자식 타입의 변수로 접근하면 부모의 기능을 모두 사용할 수 있는데 굳이 불편하기만 해보이는 부모타입의 변수로 자식 타입을 참조하는 다형적 참조가 왜 필요한가 의문이 들 수 있는데, 이부분은 다형성의 다른 이론들도 함께 알아야 이해할 수 있음
2. 다형성과 캐스팅
1) 다형성과 캐스팅
(1) CastingMain1
- Parent poly = new Child()와 같이 부모 타입의 변수를 사용하게 되면 poly.childMethod()와같이 자식 타입에 있는 기능은 호출할 수 없음
- 그러나 다운 캐스팅을 활용한 덕분에 부모 타입 변수를 자식 타입으로 임시로 캐스팅후 Child 타입의 변수에 대입하여 해당 변수를 활용하여 Child클래스에 있는 childMethod()를 호출할 수 있게됨
package poly.basic;
public class CastingMain1 {
public static void main(String[] args) {
// 부모 변수가 자식 인스턴스 참조, 다형적 참조
Parent poly = new Child();
// 단, 자식의 기능은 호출할 수 없음. 컴파일 오류 발생
// poly.childMethod();
// 다운캐스팅, 부모 타입 -> 자식 타입
Child child = (Child) poly;
child.childMethod();
}
}
/* 실행 결과
Child.childMethod
*/
(2) 다운캐스팅
- 상속관계는 부모로만 찾아서 올라갈 수 있으므로 이미 부모타입인 poly변수는 자식 타입의 메서드인 childMethod()를 호출할 수 없고 컴파일 오류가 발생함
- 이럴때는 호출하는 타입을 자식인 Child 타입으로 변경하면 인스턴스의 Child에 있는 childMethod()를 호출할 수 있음
- 그러나 Child child = poly 처럼 부모타입을 사용하는 변수를 자식 타입에 대입하려고 하면 컴파일 오류가 발생하는데 이때는 다운캐스팅이라는 기능을 사용하여 부모 타입을 잠깐 자식 타입으로 변경하면 됨
- Child child = (Child) poly 처럼 ()에 타입을 지정하면 참조 대상을 특정 타입으로 변경할 수 있으며 이렇게 특정 타입으로 변경하는 것을 캐스팅이라함
- 캐스팅을 하게 되면 poly는 Parent 타입이므로 이 타입을 (Child)를 사용하여 일시적으로 자식 타입인 Child 타입으로 변경한 후 Child child에 대입함
- 즉, 캐스팅을 한다고 해서 Parent poly의 타입이 변하는 것이 아니라 해당 참조값을 꺼내고 꺼낸 참조값이 Child 타입이 되는 것이므로 poly의 타입은 기존과 같이 Parent임
// 캐스팅 실행 순서
Child child = (Child) poly //다운캐스팅을 통해 부모타입을 자식 타입으로 변환한 다음에 대입 시도
Child child = (Child) x001 //참조값을 읽은 다음 자식 타입으로 지정
Child child = x001 //최종 결과
(3) 캐스팅 용어
- 업캐스팅(upcasting): 부모 타입으로 변경
- 다운캐스팅(downcasting): 자식 타입으로 변경
3. 캐스팅의 종류
1) 일시적 다운 캐스팅
(1-1) CastingMain2
- 자식 타입의 기능을 사용하려면 다운캐스팅 결과를 변수에 담아두고 이후에 기능을 사용하면 되는데 변수에 담아두는 과정이 번거로움
- 이런 과정 없이 일시적으로 다운캐스팅을 해서 인스턴스에 있는 하위 클래스의 기능을 바로 호출할 수 있으며 실행해보면 정상적으로 childMethod()가 호출되는 것을 확인할 수 있음
package poly.basic;
public class CastingMain2 {
public static void main(String[] args) {
Parent poly = new Child();
// 일시적 다운캐스팅 - 해당 메서드를 호출하는 순간만 다운캐스팅
((Child) poly).childMethod();
}
}
(1-2) 그림으로 설명
- Parent 타입인 poly를 임시로 Child로 변경하고 메서드를 호출할 때 Child 타입에서 찾아서 실행함
- 자바에서는 무조건 값을 복사하여 대입하므로 poly가 Child 타입으로 바뀌는 것이 아니라 해당 참조값을 꺼내고 꺼낸 참조값이 Child 타입이 되는 것임
2) 업캐스팅
(1) CastingMain3
- 현재 타입을 부모 타입으로 변경하는 것을 업캐스팅이라고 함
- Child 타입인 child변수를 Parent 타입에 대입하기 위해 캐스팅을 해보면 캐스팅 코드인 (타입)을 생략해도 정상적으로 동작함
- 업캐스팅은 생략할 수 있지만 다운 캐스팅은 생략할 수 없으며, 업캐스팅은 매우 자주 사용하기 때문에 생략하는 것을 권장함
- 자바에서 부모는 자식을 담을 수 있어서 업캐스팅은 생략해도 되고 다운캐스팅은 필요하다면 개발자가 강제로 직접 명시적으로 캐스팅을 해야하는지 궁금증이 생길 수 있는데 바로 아래에서 자세히 설명함
package poly.basic;
public class CastingMain3 {
public static void main(String[] args) {
Child child = new Child();
Parent parent1 = (Parent) child; // 업캐스팅은 생략이 가능함, 생략을 권장함
Parent parent2 = child; // 업캐스팅 생략
parent1.parentMethod();
parent2.parentMethod();
}
}
4. 다운캐스팅과 주의점
1) 다운 캐스팅과 주의점
(1) CastingMain4
- 결과적으로 다운캐스팅은 잘못하면 심각한 런타임 오류가 발생할 수 있음
- 실행 결과를 보면 child1.childMethod()는 잘 호출되었지만 child2.childMethod()는 실행되지 못하고 오류가 발생함
package poly.basic;
// 다운캐스팅을 자동으로 하지 않는 이유
public class CastingMain4 {
public static void main(String[] args) {
Parent parent1 = new Child(); // Parent 타입으로 Child 인스턴스 생성
Child child1 = (Child) parent1;
child1.childMethod(); // 문제 없음
Parent parent2 = new Parent(); // Parent 타입으로 Parent 인스턴스 생성
Child child2 = (Child) parent2; // 런타임 오류 - ClassCastException
child2.childMethod(); // 실행 불가
}
}
/* 실행 결과
Child.childMethod
Exception in thread "main" java.lang.ClassCastException:
class poly.basic.Parent cannot be cast to class poly.basic.Child (poly.basic.Parent and poly.basic.Child are in unnamed module of loader 'app')
at poly.basic.CastingMain4.main(CastingMain4.java:11)
*/
(2) 다운캐스팅이 가능한 경우와 불가능한 경우
- 예제의 parent1의 경우 다운캐스팅을 해도 문제가 없음
- 예제의 parent2를 다운캐스팅을 하면 ClassCastException이라는 심각한 런타임 오류가 발생하는데 new Parent()로 부모 타입으로 객체를 생성했기 때문에 메모리 상에 자식 타입은 전혀 존재하지 않음
- 인스턴스 생성 결과를 parent2에 담아두는데 까지는 문제가 발생하지 않지만 parent2를 Child 타입으로 다운캐스팅을하면 메모리 상에 Child 자체가 존재하지 않아 Child 자체를 사용할 수 없음
- 자바에서는 이렇게 사용할 수 없는 타입으로 다운캐스팅하는 경우에 ClassCastException이라는 예외를 발생시킴
- 예외가 발생하면 다음 동작이 실행되지 않고 프로그램이 종료되어 child2.childMethod() 코드 자체가 실행되지 않음
2) 업캐스팅이 안전하고 다운캐스팅이 위험한 이유
(1) 업캐스팅은 이런 문제가 절대로 발생하지 않음
- 업캐스팅은 이런 문제가 절대 발생할 수 없는데 이유는 객체를 생성하면 해당 타입의 상위 부모 타입은 모두 함께 생성되기 때문임
- 따라서 위로만 타입을 변경하는 업캐스팅은 메모리 상에 인스턴스가 모두 존재하므로 항상 안전하며 캐스팅도 생략할 수 있는 것임
- 반면 다운캐스팅의 경우에는 객체 생성시 해당 타입의 상위 부모 타입은 모두 함께 생성되지만 자식 타입은 생성되지 않기 때문에 인스턴스에 존재하지 않는 하위 타입으로 캐스팅하는 문제가 발생할 수 있게 됨
- 즉 개발자가 이런 문제를 인지하고 사용해야 한다는 의미로 명시적 캐스팅을 해주어야 함
(2) 업캐스팅 - 그림 설명
- 클래스 A, B, C는 상속관계이므로 new C()로 인스턴스를 생성하면 인스턴스 내부에 자신과 부모인 A, B, C가 모두 생성됨
- 따라서 C의 부모 타입인 A, B, C 모두 C 인스턴스를 참조할 수 있으며 상위로 올라가는 업캐스팅은 인스턴스 내부에 부모가 모두 생성되기 때문에 문제가 발생하지 않음
- A a = new C(): A로 업캐스팅
- B b = new C(): B로 업캐스팅
- C c = new C(): 자신과 같은 타입
(3) 다운캐스팅 - 그림 설명
- new B()로 인스턴스를 생성하면 인스턴스 내부에 자신과 부모인 A, B가 생성이 되므로 A, B모두 B 인스턴스를 참조할 수 있음
- 객체를 생성할 때 하위 자식은 생성되지 않기 때문에 하위로 내려가는 다운캐스팅은 인스턴스 내부에 없는 부분을 선택하는 문제가 발생할 수 있음
- C c = new B(): 하위 타입은 대입할 수 없으므로 컴파일 오류 발생
- C c = new (C) new B(): 하위 타입으로 강제 다운캐스팅을하면 B인스턴스에 C와 관련된 부분이 없으므로 잘못된 캐스팅이 되어 ClassCastException 런타임 오류가 발생함
(4) 컴파일 오류 vs 런타임 오류
- 컴파일 오류는 변수명 오타, 잘못된 클래스 이름 사용 등 자바 프로그램을 실행하기 전에 발생하는 오류인데 이런 오류는 IDE에서 즉시 확인할 수 있기 때문에 안전하고 좋은 오류임
- 반면, 런타임 오류는 프로그램이 실행되고 있는 시점에 발생하는 오류인데 IDE에서는 오류가 보이지 않고 보통 고객이 해당 프로그램을 실행하는 도중에 발생하기 때문에 매우 안좋은 오류임
5. instanceof
1) instanceof
(1) CastingMain5
- 다형성에서 참조형 변수는 다양한 자식을 대상으로 참조할 수 있으므로 변수가 참조하는 인스턴스의 타입을 확인하고 싶다면instanceof키워드를 사용하면됨
- call(Parent parent) 메서드는 매개변수로 넘어온 parent가 참조하는 타입에 따라서 다른 명령을 수행하는데, 기본적으로는 parentMethod()를 호출하고 parent의 인스턴스 타입이 Child면 다운캐스팅을 하고childMethod()도 호출하도록 작성되었음
- 출력해보면 parent2는 Child인스턴스이므로 parentMethod()메소드 호출에 이어서 childMethod()메소드도 호출되는 것을 확인할 수 있음
- 지금처럼 다운캐스팅을 수행하기 전에는 먼저 instanceof를 사용하여 원하는 타입으로 변경이 가능한지 확인한 다음에 다운캐스팅을 수행하는 것이 안전함
package poly.basic;
public class CastingMain5 {
public static void main(String[] args) {
Parent parent1 = new Parent();
System.out.println("parent1 호출");
call(parent1);
Parent parent2 = new Child();
System.out.println("parent2 호출");
call(parent2);
}
private static void call(Parent parent) {
parent.parentMethod();
if (parent instanceof Child) {
System.out.println("Child 인스턴스 맞음");
Child child = (Child) parent;
child.childMethod();
}
}
}
/* 실행 결과
parent1 호출
Parent.parentMethod
parent2 호출
Parent.parentMethod
Child 인스턴스 맞음
Child.childMethod
*/
(2) instanceof 동작
- call()메서드가 처음 호출할 때 parent는 Parent의 인스턴스를 참조하므로 instanceof의 결과가 false를 반환함
- 다음 call()메서드가 호출할 때 parent는 Child의 인스턴스를 참조하므로 instanceof의 결과는 true를 반환하고 나머지 로직을 수행하게 됨
- 참고로 instanceof 키워드는 오른쪽 대상의 자식 타입을 왼쪽에서 참조하는 경우에도 true를 반환하는데 쉽게 이야기해서 오른쪽에 있는 타입에 왼쪽에 있는 인스턴스 타입이 들어갈 수 있는지 대입해보고 대입이 가능하면 true, 불가능하면 false가 됨
new Parent() instanceof Parent
Parent p = new Parent() //같은 타입 true
new Child() instanceof Parent
Parent p = new Child() //부모는 자식을 담을 수 있음 true
new Parent() instanceof Child
Child c = new Parent() //자식은 부모를 담을 수 없음 false
new Child() instanceof Child
Child c = new Child() //같은 타입 true
(3) 자바 16 - Pattern Matching for instanceof
- 자바 16부터는 instanceof를 사용하면서 동시에 변수를 선언할 수 있음
- 현재는 실무에서 자주 사용하진 않는데 점차 많이 사용할 것으로 보임
package poly.basic;
public class CastingMain6 {
public static void main(String[] args) {
// ... 기존 코드 동일 생략
}
private static void call(Parent parent) {
parent.parentMethod();
// Child 인스턴스인 경우 childMethod() 실행
if (parent instanceof Child child) {
System.out.println("Child 인스턴스 맞음");
child.childMethod();
}
}
}
6. 다형성과 메서드 오버라이딩
1) 다형성과 메서드 오버라이딩
(1) 설명
- 다형성을 이루는 또 하나의 중요한 핵심 이론은 메서드 오버라이딩인데 꼭 기억해야할 점은 오버라이딩 된 메서드가 항상 우선권을 가진다는 점임
- 그래서 이름도 기존 기능을 덮어 새로운 기능을 재정의 한다는 뜻의 오버라이딩임
- 메서드 오버라이딩의 진짜 힘은 다형성과 함께 사용할 때 나타남
(2) UML 설명
- Parent, Child 모두 value라는 멤버 변수를 가지고 있음
- Parent, Child 모두 method()라는 같은 메서드를 가지고 있으며 Child에서 오버라이딩하였음
- 멤버 변수는 오버라이딩 되지 않으며 메서드는 오버라이딩이 됨
(3) Parent
package poly.overriding;
public class Parent {
public String value = "Parent";
public void method() {
System.out.println("Parent.method");
}
}
(4) Child
- Parent를 상속받고 method()를 오버라이딩
package poly.overriding;
public class Child extends Parent {
public String value = "child";
@Override
public void method() {
System.out.println("Child.method");
}
}
(5) OverridingMain
- 본인 타입 변수가 본인 인스턴스를 참조하는 부분은 계속 반복 학습했으므로 별다른것은 없음
- 그러나 부모 변수가 자식 인스턴스를 참조하는 다형적 참조인 경우 poly.method()를 보면 Parent 타입 변수로 method()를 호출했음에도 오버라이딩된 Child의 method()가 호출된 것을 확인할 수 있음
package poly.overriding;
public class OverridingMain {
public static void main(String[] args) {
// 자식 변수가 자식 인스턴스 참조
Child child = new Child();
System.out.println("Child -> Child");
System.out.println("value = " + child.value);
child.method();
// 부모 변수가 부모 인스턴스 참조
Parent parent = new Parent();
System.out.println("Parent -> Parent");
System.out.println("value = " + parent.value);
parent.method();
// 부모 변수가 자식 인스턴스 참조(다형적 참조)
Parent poly = new Child();
System.out.println("Parent -> Child");
System.out.println("value = " + poly.value); // 변수는 오버라이딩 X
poly.method(); // 메서드 오버라이딩
}
}
/* 실행 결과
Child -> Child
value = child
Child.method
Parent -> Parent
value = Parent
Parent.method
Parent -> Child
value = Parent
Child.method
*/
(6) 본인 타입의 변수가 본인 인스턴스를 참조
- child 변수는 Child 타입이므로 child.value, child.method()를 호출하면 인스턴스의 Child 타입에서 기능을 찾아서 실행함
- 마찬가지로 parent 변수는 Parent 이므로 parent.value, parent.method()를 호출하면 인스턴스의 Parent 타입에서 기능을 찾아서 실행함
(7) Parent -> Child, 다형적 참조 - 중요**
- poly 변수는 Parent 타입이므로 poly.value, poly.method()를 호출하면 인스턴스의 Parent 타입에서 기능을 찾아서 실행함
- poly.value: Parent 타입에 있는 value 값을 읽음
- poly.method(): Parent 타입에 있는 method()를 실행하려고하는데 하위 타입인 Child.method()가 오버라이딩 되어있으므로 Parent.method()가 아닌 Child.method()가 실행됨
- 오버라이딩 된 메서드는 항상 우선권을 가짐
- 즉, 자식에서도 오버라이딩하고 손자에서도 같은 메서드를 오버라이딩하면 손자의 오버라이딩 메서드가 우선권을 가지며 가장 하위 자식의 오버라이딩 된 메서드가 우선권을 가짐
(8) 정리
- 다형성을 이루는 핵심 이론은 다형적 참조와 메서드 오버라이딩이며 이 둘을 이해하고 나면 진정한 다형성의 위력을 알 수 있게됨
- 다형적 참조: 하나의 변수 타입으로 다양한 자식 인스턴스를 참조할 수 있는 기능
- 메서드 오버라이딩: 기존 기능을 하위 타입에서 새로운 기능으로 재정의하고 오버라이딩 된 메서드는 항상 우선권을 가짐
출처 : 인프런 - 김영한의 실전 자바 - 기본편 (유료) / 김영한님
유료 강의이므로 정리에 초점을 두고 코드는 일부만 인용