업캐스팅 다운캐스팅

Mia Lee·2021년 12월 20일
0

JAVA

목록 보기
76/98
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() 메서드!");
		
	}
}

















0개의 댓글