다형적 참조
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 | 
 
                    
                   
                    
                  