다형성이란?
다형성은 한 객체가 여러 타입의 객체로 취급될 수 있는 능력을 뜻한다. 보통 하나의 객체는 하나의 타입으로 고정되어 있는데,
다형성을 사용하면 하나의 객체가 다른 타입으로 사용될 수 있다.
다형적 참조
- 부모는 자식을 품을 수 있다. (자식 클래스를 참조할 수 있다.)
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.childMethod();
child.parentMethod();
//부모 변수가 자식 인스턴스를 참조 (다형적 참조)
System.out.println("Parent -> Child");
Parent poly = new Child();
poly.parentMethod();
// Child child1 = new Parent(); // 자식은 부모를 담을 수 없다.
//자식의 메서드는 호출할 수 없다.
// poly.childMethod();
}
}
다형적 참조의 한계
- 이전 상속파트에서 학습했던 내용에 인스턴스 안에서 실행할 타입을 결정하는 건 호출한 데이터 타입에 따라서 실행된다고 배웠다.
poly.childMethod( ); 코드는 Child 인스턴스 이긴 하지만 Parent 타입으로 호출했기 때문에 Child Class까지 내려가지 않는다.
Parent에서만 실행되기 때문에. childMethod( )는 실행할 수 없다. 오직 parentMethod( )만 실행이 가능하다.
다운캐스팅
위와 같은 문제로, 데이터 타입의 문제로 poly.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) poly).childMethod();
메서드를 호출하는 순간만 다운캐스팅을 하는 방법
업캐스팅
다운캐스팅과 반대로 현재 타입을 부모 타입으로 변경하는 것을 업캐스팅이라 한다.
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();
}
}
(부모클래스는 자식클래스를 담을 수 있다.)
업캐스팅은 괄호를 사용하지않고 생략할 수 있다. 생략을 권장한다고 한다.
업캐스팅은 생략하는데, 다운캐스팅은 왜 명시적으로 표현해야 할까?
Parent 타입으로 객체가 생성되었는데, 객체가 생성 될 때 상위 클래스는 생성하지만 하위 클래스는 생성하지 않는다.
따라서 Child 인스턴스가 없으므로 캐스팅이 불가능하다. 자식 타입은 생성되지 않기때문에 개발자가 이를 인지한 상태에서
코드를 작성했다는 의미로 명시적으로 표현을 해주어야 한다.
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();
}
}
}
instanceof를 통해 보다 안전하게 다운캐스팅을 할 수 있다.
jdk 16버전에서는 instanceOf에 변수선언까지 가능하다.
private static void call(Parent parent) {
parent.parentMethod();
// child 인스턴스 인경우 childMethod() 실행
if (parent instanceof Child child) {
System.out.println("Child 인스턴스 맞음");
child.childMethod();
}
}
jdk16버전에선 instanceof 기능이 개선되었다고 한다.
다형성과 메서드 오버라이딩
메서드 오버라이딩의 핵심은 오버라이딩 된 메서드가 절대적으로 우선권을 가진다는 것이다.
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(); // 메서드 오버라이딩O
}
}
필드는 오버라이딩이 불가능하다. 따라서 poly.value는 Parent의 value를 가져오게 된다.
메서드는 오버라이딩이 가능하다. 따라서 poly.method( );는 Child의 메서드를 실행한다. (오버라이딩 된 메서드는 우선권을 가지기 때문)
다운캐스팅과 업캐스팅, 메서드 오버라이딩을 배웠다. 다음섹션에서 다운캐스팅을 사용하는 이유에 대해 배우는데
아직까지 굳이 다운캐스팅을 해야할 이유를 못느끼고 있다.
'Java' 카테고리의 다른 글
다형성(3) - OCP (0) | 2024.06.13 |
---|---|
다형성 (2) - 추상클래스, 인터페이스 (0) | 2024.06.12 |
상속 (0) | 2024.06.07 |
final (0) | 2024.06.06 |
접근 제어자 (0) | 2024.05.28 |