class testA {
int a;
testA(){
System.out.println("testA()");
}
testA(int a) {
System.out.println("testA(int a)");
}
void methodA() {
System.out.println("A");
}
}
class testB extends testA{
int b;
testB(){
//super();
super(10);
System.out.println("testB()");
}
void methodB() {
System.out.println("testB");
}
@Override
void methodA() {
// TODO Auto-generated method stub
System.out.println("BA");
}
}
class testC extends testB {
int c;
testC(){
super();
System.out.println("testC()");
}
void methodC() {
System.out.println("testC");
}
@Override
void methodA() {
// TODO Auto-generated method stub
System.out.println("CA");
}
}
public class UpcastingDowncasting {
public static void main(String[] args) {
//부모클래스의 참조변수는 자식 객체를 참조할 수 있음 (다형성)
//testA 타입의 참조변수 = obb , obc
testA oba = new testA();
testA obb = new testB(); // 업케스팅
testA obc = new testC();
//장점 - 하나의 타입을통해 관리를해도 재정의된 메서드가 나옴
obb.methodA(); // 재정의된(override)된 자식 메서드 호출 (동적 바인딩)
obc.methodA();
// 업케스팅 시 부모참조 변수로 부모모양만 보이지만
//자식클래스에서 부모클래스의 메서드를 재정의하면 그것이 출력
업케스팅 : 부모클래스의 참조변수는 자식 객체를 참조할 수 있다(다형성)
무슨 뜻인지 처음에는 감이 안잡혔으나 그림을 통해 이해를 하게 되었다.
testA obc = new testC(); 에서 testA를 이용한 obc라는 참조변수를 만들었고
이는 testC() 라는 자식 객체를 참조하였다.
이렇게 사용하게되면 하나의 타입을 통해 관리를 해도 재정의된 매서드를 사용할 수 있다는 것을 알게 되었다.
obb.methodA(); // 재정의된(override)된 자식 메서드 호출 (동적 바인딩)
obc.methodA();
이러한 방법을 업케스팅이라 한다.
하지만 단점도 있는데 부모클래스로 참조변수를 만들게되면 그것을 상속한 자식객체의 오버라이딩 된 메서드를 볼수 없다라는것을 알게 되었다.
왜냐하면 obc 참조변수를 만들때 그림과같이 A와 C 부분이 만들어졌지만
obc가 볼수 있는 부분은 A부분이기때문에 C부분의 내부메서드를 볼수가없다
오버라이딩부분 제외
이러한 부분을 보완하기 위해 다운케스팅을 하게 된다
난 부모클래스로 만든 참조변수 obc를 이용해 methodC()를 사용하고싶으면
다운케스팅, instanceof 를 사용하게 된다
testA[] ob = new testA[] {oba, obb, obc };
for(int i = 0; i < ob.length ; i++) {
ob[i].methodA();
}
// obb. 해보면 객체만 보임
testB tmp = (testB)obb; // 다운케스팅
System.out.println(obb);
System.out.println(tmp);
// tmp. 다운케스팅을한 tmp를 보면 B메서드도 볼수 있음
tmp.methodB();
// 다은케스팅 다른 방법 - instanceof
System.out.println(obb instanceof testA);
System.out.println(obb instanceof testC);
System.out.println(obc instanceof testC);
System.out.println("=========");
for(int i = 0; i < ob.length ; i++) {
ob[i].methodA();
if(ob[i] instanceof testB) {
testB b = (testB)ob[i];
b.methodB();
}else if(ob[i] instanceof testC) {
testC c = (testC)ob[i];
c.methodC();
첫번째 방법은 obb가 현제 testA로 생성되어서 tmp라는 참조변수를 testB타입으로 만들어주고 그것을 이용해 testB에 있는 메서드를 사용하면된다
2번째 방법으로는 instanceof 를 사용하여 해당 부분을 가지고 있을 때
그 타입의 참조변수를 생성하고 그것을 이용하면 된다.
그림으로 표현하면 이렇다
시야를 넓힌다는 생각을 가지면 편하다 obb 는 A , B 모두 포함하지만
testA라는 부모클래스를이용해 참조변수를 만들었기 때문에 A만 볼수 있다.
시야를 넓히기위해
testB tmp = (testB)obb 를 사용해 tmp가 b그림처럼 만들고
그아래에있는 기능도 사용할 수 있겠금 만드는 방식이다