다형적 참조
public class Parent {
public void parentMethod() {
System.out.println("Parent.parentMethod");
}
}
public class Child extends Parent {
public void childMethod() {
System.out.println("Child.childMethod");
}
}
public class PolyMain {
public static void main(String[] args) {
Parent poly = new Child(); // 다형적 참조
poly.parentMethod();
}
}
- 부모 타입의 변수가 자식 인스턴스를 참조(Parent poly = new Child())
- 이 경우 자식 타입인 Child를 생성했기 때문에 메모리 상에 Child와 Parent가 모두 생성
- 생성된 참조값을 Parent 타입의 변수인 poly에 담아둠
- 반대로 자식 타입은 부모 타입을 담을 수 없음
다형적 참조와 인스턴스 실행
- poly.parentMethod()를 호출하면 먼저 참조값을 사용해서 인스턴스를 찾음
- 다음으로 인스턴스 안에서 실행할 타입도 찾음
- 위의 경우 Parent 클래스부터 시작해서 필요한 기능을 찾음
- 인스턴스의 Parent 클래스에 parentMethod()를 호출
다형적 참조의 한계
- 호출자인 poly는 Parent 타입이므로 Parent 클래스부터 시작해서 필요한 기능을 찾음
- 그런데 상속 관계는 부모 방향으로 찾아 올라갈 수는 있지만 자식 방향으로 찾아 내려갈 수는 없음
- Parent는 부모 타입이고 상위에 부모가 없기때문에 childMethod()를 찾을 수 없으므로 컴파일 오류 발생
다형성과 캐스팅
Child child = (Child) poly // Parent poly
- (타입) 처럼 괄호와 그 사이에 타입을 지정하면 참조 대상을 특정 타입으로 변경 가능
- 특정 타입으로 변경하는 것을 캐스팅이라고 함
1. 다운캐스팅
public class TestMain {
public static void main(String[] args) {
//부모 변수가 자식 인스턴스 참조(다형적 참조)
Parent poly = new Child();
//단 자식의 기능은 호출할 수 없다. 컴파일 오류 발생
//poly.childMethod();
//다운캐스팅 - 다운캐스팅 결과를 변수에 담아두는 과정이 필요
Child child = (Child) poly;
child.childMethod();
//일시적 다운캐스팅 - 해당 메서드를 호출하는 순간만 다운캐스팅
((Child) poly).childMethod();
}
}
- 자식 타입으로 변경하는 것을 다운캐스팅
- 캐스팅을 한다고 해서 Parent poly의 타입이 변하는 것은 아님
- 해당 참조값을 꺼내고 꺼낸 참조값이 Child 타입이 되는 것
- 따라서 poly의 타입은 Parent로 그대로 유지
- 일시적 다운캐스팅을 사용하면 별도의 변수 없이 인스턴스의 자식 타입의 기능을 사용할 수 있음
2. 업캐스팅
public class TestMain {
public static void main(String[] args) {
Child child = new Child();
Parent parent1 = (Parent) child; //업캐스팅은 생략 가능, 생략 권장
Parent parent2 = child; //업캐스팅 생략
parent1.parentMethod();
parent2.parentMethod();
}
}
- 부모 타입으로 변경하는 것을 업캐스팅
- 업캐스팅은 생략 가능
- 자바에서 부모는 자식을 담을 수 있음
다운캐스팅 주의점
public class TestMain {
public static void main(String[] args) {
Parent parent1 = new Child();
Child child1 = (Child) parent1;
child1.childMethod();
Parent parent2 = new Parent();
Child child2 = (Child) parent2; // 런타임 오류 - ClassCastException
child2.childMethod(); // 실행 불가
}
}
- new Parent()로 부모 타입으로 객체를 생성. 따라서 메모리 상에 자식 타입은 존재하지 않음
- parent2를 Child 타입으로 다운캐스팅 하지만 메모리 상에 Child는 존재하지 않아 사용 불가
- 사용할 수 없는 타입으로 다운캐스팅하는 경우에 ClassCastException 예외 발생
다운캐스팅이 가능한 경우 메모리 구조
다운캐스팅이 불가능한 경우 메모리 구조
업캐스팅과의 차이
- 업캐스팅의 경우 객체 생성 시 해당 타입의 상위 부모 타입은 모두 함께 생성
- 따라서 위로만 타입을 변경하는 업캐스팅은 메모리 상에 인스턴스가 모두 존재하기 때문에 안전
- new C()로 인스턴스를 생성하면 인스턴스 내부에 자신과 부모인 A, B, C 모두 생성
- A a = new C() : A로 업캐스팅
- B b = new C() : B로 업캐스팅
- C c = new C() : 자신과 같은 타입
- 객체를 생성하면 부모 타입은 모두 함께 생성되지만 자식 타입은 생성되지 않기 때문에 다운캐스팅의 경우 인스턴스에 존재하지 않는 하위 타입으로 캐스팅하는 경우 문제 발생
- new B()로 인스턴스를 생성하면 인스턴스 내부에 자신과 부모인 A, B 모두 생성
- A a = new B() : A로 업캐스팅
- B b = new B() : 자신과 같은 타입
- C c = new B() : 하위 타입 대입 불가, 컴파일 오류
- C c = (C) new B() : 강제 다운캐스팅, 하지만 B 인스턴스에 C와 관련된 부분이 없으므로 ClassCastException 런타임 오류 발생
'Java > Basic' 카테고리의 다른 글
다형성과 메서드 오버라이딩 (0) | 2024.12.31 |
---|---|
instanceof (0) | 2024.12.31 |
상속 (0) | 2024.12.12 |
static (1) | 2024.12.08 |
메모리 구조 (2) | 2024.12.08 |