package ex_type_castin;
public class Ex1 {
public static void main(String[] args) {
/*
* 형변환(Type Casting)
*
* 1. 기본형변환
* - 기본 데이터타입 8가지 중 boolean을 제외한 나머지 7가지 타입끼리의 형변환
* - 작은 타입에서 큰 타입으로 변환 시 자동(묵시적) 형변환,
* 큰 타입에서 작은 타입으로 변환 시 강제(명시적) 형변환
* - 강제 형변환 시 반드시 형변환 연산자를 사용하여 변환될 타입을 명시!
* => 단, 강제 형변환 후에는 오버플로우가 발생할 위험이 있음
*
* 2. 참조(Reference Type)형변환
* 1) 업캐스팅(Up Casting)
*
* < 기본 문법 >
* 슈퍼클래스타입 변수명 = 서브클래스인스턴스;
*
* 2) 다운캐스팅(Down Casting)
*
* < 기본 문법 >
* 서브클래스타입 변수명 = (서브클래스타입) 슈퍼클래스인스턴스;
*
*/
int a = 10; // 기본형 int타입 변수 선언
long l = a; // long 타입 변수에 int 타입값을 전달
// => int타입 값이 long 타입으로 변환됨
// Child3 클래스의 인스턴스(c) 생성
Child3 c = new Child3(); // 서브클래스의 인스턴스 생성
// 서브클래스의 인스턴스 c를 통해 접근 가능한 메서드 : 2개
c.parentPrn(); // 상속받은 메서드
c.childPrn(); // 자신의 클래스에서 정의한 메서드
// Parent3 타입 변수 p를 선언하여 Child3 클래스의 인스턴스 전달
// 슈퍼클래스 타입 참조 변수 p 선언
Parent3 p;
p = c; // 서브클래스의 인스턴스 주소를 슈퍼클래스타입 변수에 전달
// => Child 타입 -> Parent 타입으로 변환됨(업캐스팅)
// => 업캐스팅은 자동 형변환이 가능하므로 형변환 연산자 생략 가능
// Parent 타입 변수 p를 통해 접근 가능한 메서드 : 1개
p.parentPrn(); // 상속받은 메서드는 호출 가능
// p.childPrn(); // 오류 발생! 서브클래스에서 정의한 메서드는 호출 불가능
// => 업캐스팅 후에는 참조 영역에 대한 축소가 발생하므로 상속된 멤버 외의
// 서브클래스에서 정의한 멤버는 접근 불가능하게 됨.
// 즉, 서브클래스의 멤버는 보이지 않게 됨
System.out.println("p와 c의 주소값이 같은가? " + (p == c));
// => 두 변수가 동일한 객체를 잠조 하고 있다는 뜻!
System.out.println("===========================================");
// 슈퍼클래스타입 인스턴스(p2) 생성
Parent3 p2 = new Parent3();
// 슈퍼클래스타입으로 접근 가능한 메서드 : 1개
p2.parentPrn();
// 서브클래스타입 변수 선언 및 슈퍼클래스타입 인스턴스 전달
// Child3 c2 = p2; // 오류 발생! 다운캐스팅은 자동 형변환이 지원되지 않음
// => 명시적(강제) 형변환 필요
// Child3 c2 = (Child3) p2; // 서브클래스타입을 명시하여 강제 형변환
// => 형변환 후에도 오류 발생
// => 다운캐스팅을 하게 되면 참조 영역에 대한 확대가 일어남
// c2.parentPrn(); // Parent 인스턴스에 존재하는 메서드
// c2.childPrn(); // Parent 인스턴스에 존재하지 않는 메서드
// => childPrn() 메서드는 실제 인스턴스에는 존재하지 않지만 Child3 타입 클래스가 알고 있는
// 메서드이므로 접근 가능하게 됨. 그러나, 실제 존재하지 않는 메서드를 접근하게 되므로 오류!
// => 존재하지 않는 영역에 대한 참조의 위험 때문에 다운캐스팅은 자동 형변환이 지원되지 않으며
// 강제 형변환을 하더라도 실행 시점에서 논리적 오류가 발생!
System.out.println("====================================");
// 다운캐스팅이 허용되는 경우
// 서브클래스의 인스턴스 생성
// Child3 c3 = new Child3();
// Parent3 p3 = c3; // 업캐스팅
// 위의 두 문장을 하나로 결합 가능
Parent3 p3 = new Child3(); // 업캐스팅
// 슈퍼클래스(Parent3) 타입으로 접근 가능한 메서드 : 1개
p3.parentPrn(); // 상속받은 메서드
// 이미 업캐스팅 된 인스턴스를 다시 다운캐스팅
// Child3 c3 = p3; // 명시적 형변환 필요
Child3 c3 = (Child3) p3; // 다운캐스팅(실행 시 오류 발생하지 않음!)
// 서브클래스(Child) 타입으로 접근 가능한 메서드 : 2개
c3.parentPrn(); // 상속받은 메서드
c3.childPrn(); // 서브클래스에서 정의한 메서드
// 결론!
// 이전에 이미 업캐스팅 되어 참조영역이 축속되었던 인스턴스를 다시 다운캐스팅을 통해
// 참조영역이 확대되면 접근 범위에 아무런 문제가 없으므로 사용이 가능!
// 따라서, 레퍼런스 형변환 시에는 상속 관계를 고려하여 알맞은 형변환 방식을 선택해서 변환!
}
}
class Parent3 {
public void parentPrn() {
System.out.println("슈퍼클래스의 parentPrn() 메서드!");
}
}
// Child3 클래스 정의 - Parent3 클래스를 상속
// childPrn() 메서드 정의 - "서브클래스의 childPrn() 메서드!" 출력
class Child3 extends Parent3 {
public void childPrn() {
System.out.println("서브클래스의 childPrn() 메서드!");
}
}