상속 관계에 있는 클래스 간의 형변환(Casting)
기본자료형은 연산하려는 두 데이터의 자료형이 다를 때, 연산을 수행할 수 있도록 명시적 또는 자동으로 자료형을 변환시킨다.
클래스의 경우, 연산하려는 두 클래스가 서로 다를 때 어떻게 해야할까?
클래스의 연산이라하면 인스턴스를 참조하기 위한 대입연산을 살펴볼 수 있다. 일단 대입연산을 하려면 형변환을 해야할 것이다. 하지만 상속 관계가 아닌 두 클래스는 서로 형변환이 불가능하다.
클래스의 형변환에서 형변환의 가능 여부를 결정하는 핵심은 『어떤 클래스로 생성한 인스턴스』를 형변환하는가이다. 앞서 포스팅 자바 15-1의 '상속'에서 하위 클래스는 인스턴스를 생성할 때 상위 클래스도 메모리로 퍼올린다고 했다. 하위 클래스는 상속받은 상위 클래스를 꿰뚫고 있다. 하지만 상위 클래스는 자신의 자식 클래스가 존재는 하는지 조차 알 수 없다. 자바에서 상속은 하위 클래스가 extends 키워드로 상위 클래스를 결정하는 구조이기 때문이다.
업캐스팅(Upcasting)
하위(자식) 클래스 → 상위(부모) 클래스로 형변환 하는 것을 말한다.
- 업캐스팅은 항상 가능하다. 하위 클래스의 객체는 항상 메모리에 상위 클래스를 갖고가기 때문에 상위 클래스로 변환되기 위한 요소들을 가지고 있다.
※ 업캐스팅이 되어도 재정의(Overriding, 덮어쓰기)한 메소드는 원래의 기능으로 되돌릴 수 없다. 예제 코드 참고
다운캐스팅(Downcasting)
상위(부모) 클래스 → 하위(자식) 클래스로 형변환 하는 것을 말한다.
- 다운캐스팅은 상황에 따라 가능할 수도, 불가능할 수도 있다. 다운캐스팅의 가능 여부의 핵심은 인스턴스가 어떤 클래스로 생성된 인스턴스인지가 중요하다. (new 하위() 인지, new 상위() 인지.)
하위 클래스로 생성된 인스턴스를 상위로 업캐스팅 했다가, 다시 하위로 다운캐스팅 하는 것은 충분히 가능하다(상위 클래스에 대한 메모리도 가지고 있기 때문). 하지만 상위 클래스로 생성된 인스턴스를 하위로 다운캐스팅하려면 하위가 되기 위한 내용물이 뭔지 알아야 하는데 전혀 모르기 때문에 런타임 에러가 발생한다. 상속 관계에서 상위 클래스의 인스턴스가 생성될 때는 하위 클래스를 메모리에 올리지 않는다. 존재자체 모른다.
다운캐스팅이 정상적으로 이루어지는 경우
new Sub(); // 하위 인스턴스 생성 Super = Sub; // 업 캐스팅. 업캐스팅은 항상 정상. Sub = Super; // 다운캐스팅 에러 발생. 자동형변환 규칙 위배. Sub = (Sub)Super; // 다운 캐스팅 정상. 명시적 형변환.
다운 캐스팅이 정상적으로 이루어지지 않는 경우
new Super(); // 상위 인스턴스 생성 Sub = Super; // 에러 발생. 메모리에 하위 클래스가 없기때문에 다운캐스팅 조차 불가능 Sub= (Sub)Super; // 다운 캐스팅. 하지만 런타임 에러 발생할 것임. // 명시적으로 변환은 했지만 생성된 인스턴스가 상위 클래스의 객체라서 하위 클래스의 정보가 1도 없음
상속 관계에 있는 클래스 간의 형변환 관찰 코드 - 업캐스팅, 다운캐스팅 예제 코드
/*================================= ■■■ 클래스 고급 ■■■ - 상속 관계에 있는 클래스들 간의 캐스팅 - 업 캐스팅, 다운 캐스팅 =================================*/ // super class, 부모 클래스, 상위 클래스 class Super { public int a=10, b=20; public void write() { System.out.println("슈퍼 클래스 write() 메소드..."); } public int hap() { return a + b; } } // sub class, 자식 클래스, 하위 클래스 class Sub extends Super { public int b=100, c=200; @Override public int hap() { return a + b + c; } public void print() { System.out.println("서브 클래스 write() 메소드..."); } } // main() 메소드를 포함하고 있는 외부의 다른 클래스(동일 패키지) public class Test { public static void main(String[] args) { Sub ob1 = new Sub(); // 하위 class 기반의 인스턴스 생성 // 부모가 가진 메모리 영역과 자식이 가진 메모리 영역은 따로따로 할당된다. // (따로 할당된다는 것은 형변환이 됬을 때 같은 이름의 변수를 구분함을 의미한다.) // 클래스 간 형변환의 가장 중요한 핵심. 처음에 상위 객체로 생성되는지. 하위 객체로 생성되는지. // ○ 업 캐스팅(하위 → 상위) //Super ob2; // 상위 class 인스턴스를 참조하는 변수 ob2 //ob2 = ob1; Super ob2 = ob1; // 위 두 줄을 한 줄로 표현 //-- 『Super ob2 = (Super)ob1;』과 동일한 구문. 자동 형변환 System.out.println("ob2.b : " + ob2.b); //--==>> ob2.b : 20 //-- 업캐스팅 후 변수b 에 접근했을 때, Super의 변수b 에 접근했음을 확인 // 하위 클래스의 객체가 생성될 때는 상위 클래스 또한 메모리를 할당받는다. ob2.write(); //--==>> 슈퍼 클래스 write() 메소드... //ob2.print(); //--==>> 에러 발생(컴파일 에러). Super로 업캐스팅 했으니 Sub의 메소드에 접근 불가능. System.out.println("합 : " + ob2.hap()); //--==>> 합 : 310 //-- hap() 메소드는 Super에 있어서 호출 가능하다. // 하지만 ob2 는 ob1 (Sub)을 업캐스팅한 상태의 객체이고 // hap() 메소드는 오버라이딩(Overriding)되어 있기 때문에 // 애초에 ob1 인스턴스가 생성되면서 Super가 메모리에 올라갈 때 재정의(덮어쓰기)되므로 // 『Super』의 hap() 메소드가 아니라 『Sub』에서 재정의한 hap() 메소드를 호출하게 된다. // 즉, 메소드는 업캐스팅이 되더라도 재정의(덮어쓰기)하면 원래의 기능으로 되돌릴 수 없다. // ○ 다운 캐스팅 ((Sub)ob2).print(); //--==>> 서브 클래스 write() 메소드... // ※ 추가 관찰 -------------------------------------------------------------------- // 다운 캐스팅 가능 여부 Super ob3 = new Super(); // 상위 class 기반의 인스턴스 생성 Sub ob4; // 하위 class 인스턴스를 참조하는 변수 ob4 //ob4 = ob3; //--==>> 에러 발생(컴파일 에러) //-- 상위 객체는 하위 객체에 담을 수(참조할 수) 없다. 자동 형변환 위배. ob4 = (Sub)ob3; // 명시적 형변환. 다운캐스팅은 된다. //--==>> 에러 발생(런타임 에러) : ClassCastException //-- 작성된 구문의 문법적인 구조만 봤을 때 다운 캐스팅이 이루어지는 상황이다. // 하지만, 정상적인 캐스팅이 이루어지지 않는다. // 현재 Sub 객체에 대해 메모리 할당이 이루어지지 않은 상태이기 때문에 // 다운 캐스팅은 불가능한 것이다. } }
'자바 풀스택 과정 수업 정리 > 자바' 카테고리의 다른 글
| 자바 16-3 (2020.08.25) : 중첩클래스(중첩 내부클래스, 내부클래스, 로컬클래스, 익명클래스) (0) | 2020.09.06 |
|---|---|
| 자바 16-2 (2020.08.25) : 인터페이스 (0) | 2020.09.05 |
| 자바 15-2 (2020.08.24) : 메소드 오버라이딩(@Override), final 메소드, 추상 클래스(Abstarct) (0) | 2020.09.02 |
| 자바 15-1 (2020.08.24) : 상속, super (0) | 2020.08.29 |
| 자바 14 (2020.08.21) : 정렬 알고리즘(선택, 버블, 삽입, 향상된 버블) (0) | 2020.08.28 |




최근댓글