다형성은 객체지향 프로그래밍의 꽃!
다형성(Polymorphism)이란?
다형성은 이름 그대로 다양한 형태, 여러 형태를 의미한다.
프로그래밍에서 다형성은 한 객체가 여러 타입의 객체로 취급될 수 있는 능력을 의미한다.
보통 하나의 객체는 하나의 타입으로 고정되어 있는데, 다형성을 사용하면 하나의 객체가 다른 타입으로 사용될 수 있다.
- 다형성을 이해하기 위해 알아야할 개념
- 다형적 참조 : 부모는 자식을 품을 수 있다.
- 메서드 오버라이딩
다형적 참조 : 부모는 자식을 품을 수 있다
// Parent가 Child이 부모 클래스일 때
// 가능
// 부모 타입의 변수가 자식 인스턴스를 참조
Parent poly = new Child();
// 불가능, 컴파일 오류 발생
Child poly = new Parent();
위 코드처럼 Child 인스턴스를 Parent 타입으로 설정이 가능하고, poly.parentMethod() 실행시 아래와 같은 과정으로 함수가 호출된다.
자바에서 부모 타입은 자신은 물론이고, 자신을 기준으로 모든 자식 타입을 참조할 수 있다. 이처럼 다양한 형태를 참조할 수 있다고 해서 다형적 참조라고 한다.
다형적 참조의 한계
Parent poly = new Child(); 인 상태에서 poly.childMethod()를 호출하면 컴파일에러가 발생한다. 왜냐하면 poly의 타입은 Parent이고, 여기에 찾는 메서드가 없다면 Parent의 부모를 탐색한다(상속 관계는 부모로만 찾아서 올라갈 수 있기 때문). 하지만 childMethod()는 Parent의 자식 클래스에 있는 메서드이므로 부모에서 자식으로 함수를 호출할 수 없다. 따라서 poly.childMethod()를 찾지 못해 컴파일 에러가 발생한다.
캐스팅
- 업캐스팅 : 자식 타입 → 부모 타입 으로 형변환
- 다운캐스팅 : 부모 타입 → 자식 타입 으로 형변환
((Child) poly).childMethod(); // 다운캐스팅을 통해 부모타입을 자식타입으로 변환 후 기능 호출
((Child) 참조값).childMethod(); // 참조값을 읽은 다음 자식 타입으로 다운캐스팅
이때 poly의 타입이 변하는 것이 아니다. poly의 타입은 Parent로 유지되고, poly의 참조값을 꺼내고 꺼낸 참조값이 Child 타입이 된다.
업캐스팅은 생략할 수 있는 반면, 다운캐스팅은 생략할 수 없다.
이 개념은 잘 알아둬야 한다.
- 다운캐스팅이 위험한 이유
이유는 다운캐스팅은 잘못하면 심각한 런타임 오류가 발생할 수 있기 때문이다.
Parent parent2 = new Parent();
Child child2 = (Child) parent2; // 다운 캐스팅 -> ClassCaseException 발생
child2.childMethod(); // 실행 불가
위 코드를 실행하면 런타임 오류인 ClassCastException이 발생한다. 이 예외가 발생하는 이유는 다음과 같다.
parent2 변수에 Parent 인스턴스의 참조값을 저장했기 때문에 해당 위치(참조)에는 Child 인스턴스가 없고, Parent 인스턴스만 있을 뿐이다. 이때 Child로 다운캐스팅 후 Child의 메서드를 호출한다고해도 Child 인스턴스 자체가 없기 때문에 ClassCastException(사용할 수 없는 타입으로 다운캐스팅할 때 발생) 예외가 발생한다.
→ 다운 캐스팅의 경우, 부모 타입은 모두 함께 생성되지만 자식타입의 인스턴스는 생성되지 않기 때문에 존재하지 않는 하위 타입으로 캐스팅하는 문제가 발생할 수 있다.
- 업캐스팅이 안전한 이유
업캐스팅의 경우, 이런 문제가 절대로 발생하지 않는다. 왜냐하면 객체 생성시 해당 타입의 상위 부모 타입이 모두 함께 생성되기 때문이다. 따라서 메모리 상에 자식 인스턴스 포함 그의 모든 부모 인스턴스가 모두 존재하기 때문에 항상 안전해야 한다. 따라서 업캐스팅을 생략할 수 있다.
따라서, 웬만하면 다운캐스팅은 사용하지 말자!
instanceof
instanceof는 참조형 변수가 참조하는 대상이 다양할 때, 어떤 인스턴스를 참고하는지 확인하기 위한 키워드이다. 즉, 인스턴스의 타입을 확인할 때 사용한다.
// value 변수의 타입이 B 타입 혹은 B의 자식 타입 -> true
// B b = value(new A())가 성립하면 true
value instanceof B
// 예시
new Parent() instanceof Parent // true
new Child instanceof Parent // true
메서드 오버라이딩
메서드 오버라이딩은 기존 기능을 덮어 새로운 기능으로 재정의한다는 뜻이다. 메서드 오버라이딩에서 꼭 기억해야하는 것은 다음과 같다.
오버라이딩 된 메서드가 항상 우선권을 가진다!
즉, 더 하위 자식에서 오버라이딩 된 메서드가 우선권을 갖는 것이다.
위 그림에서 처럼 Parent타입으로 method()를 호출해도, 그 자식 타입인 Child에서 method()를 오버라이딩 했다면 Child의 method()를 호출한다.
정리
다형성에서 기억해야할 것은 두가지다. 다형적 참조와 메서드 오버라이딩!
- 다형적 참조 : 하나의 변수 타입으로 다양한 자식 인스턴스를 참조할 수 있는 기능
- 메서드 오버라이딩 : 기존 기능을 하위 타입에서 새로운 기능으로 재정의. 오버라이딩된 메서드가 우선권을 가진다.
Reference
인프런 '김영한의 실전 자바 - 기본편'
'Dev Language > Java' 카테고리의 다른 글
[자바/기본] 12. 다형성과 설계 (0) | 2024.01.17 |
---|---|
[자바/기본] 11. 다형성2 (0) | 2024.01.17 |
[자바/기본] 9. 상속 (0) | 2024.01.16 |
[자바/기본] 8. final (0) | 2024.01.16 |
[자바/기본] 7. 자바 메모리 구조와 final (0) | 2024.01.16 |