본문 바로가기

Programming/JAVA

java : 상속관계의 참조변수 대입 쉽게 이해하기.(형변환, 다형성 등)

프로그래밍을 하다보면 서로 다른 타입의 변수들간의 대입관계를 정의하는 일이 종종 있습니다.
예를 들어
int b = 4;
long l =  b;
b = (int) l;

위와 같은 경우입니다. 이러한 대입관계를 형변환 대입이라고 합니다.
주의점은 크기가 작은 타입의 기본형변수는 크기가 큰 타입의 변수로 문제없이 대입을하고
또한 값 손실 같은 문제를 고려하지 않아도 되지만
크기가 작은 타입의 변수를 크기가 큰 타입의 변수로 대입을 하려고 할때에는 캐스팅이란 것을 해주어야합니다.
캐스팅이란 위 예의 세번째 라인에서 볼 수 있는 것 처럼  어떤 타입으로 형변환을 할 것인지를
대입하려는 변수 앞에 알려주어야 하는 것입니다. 
이때에는 값 손실을 감수하여야 합니다.

float l2 = 1.4f;
int b = (int)l2;
System.out.println(b);

결과는 1이 됩니다. 0.4의 값손실이 일어난 것이죠.

이러한 것은 값 기본타입의 변수들이 가질 수 있는 메모리의 크기에 따른 것입니다.

참조변수 역시도 위와 같은 대입연산을 할 수 있습니다.
그러기 위해서는 참조하는 객체의 타입에 대한 이해가 필요합니다.
서로 다른 타입간의 형변환은 불가능하지요.

하지만, 상속관계의 클래스의 객체를 참조하고 있는 변수간에는 가능합니다.

class A extends B{ .. }
class B{ .. }
B b = new A();
A a = new B(); // error

부모격의 B를 상속하고 있는 A의 객체는 B로 대입이 가능합니다.
하지만 자손격인 A는 부모격의 B의 객체를 A로 대입이 불가합니다.

그 이유는 위 굵은 글씨로 정의되어 있는 이유 때문입니다.
참조타입의 변수들이 가지고있는 것은 참조하고 있는 클래스의 변수들의 집합체인 객체의 주소를
가지고 있는 것입니다. 
따라서, 이 집합체가 가질 수 있는 메모리의 크기에 따라서 대입의 가능여부가 결정되는 것입니다.
(물론 객체의 변수들 타입까지도 이해하고 있어야겠죠;;) 

따라서 부모를 확장(extends)하여 정의된 클래스는 부모의 모든 메서드와 변수들을 가지고 있으므로
부모타입의 변수가 자식인스턴스를 참조하는 것은 문제가 안됩니다.
좀 더 쉽게 말하자면 자식클래스는 부모클래스보다 많거나 같은 메서드와 변수들을 가지고 있기때문에
부모타입의 참조변수는 사용할 수 있는 메서드와 변수가 참조중인 객체보다 결코 많을 수 없기 때문입니다.
(모두 사용이 가능하다는 것이죠)

그렇다면 자식은 부모타입의 객체를 참조할 방법이 전혀 없을까요?
값손실을 감수하면서 가능했던 기본형 타입간의 형변환을 생각해보면 쉽게 이해할 수 있습니다.
즉, 캐스팅을 통해서 자식타입의 참조변수가 사용할 수 있는 변수나 메서드에 제한을 두는 것입니다.
B b = new B();
A a = (A) b; 

이렇게 사용이 가능합니다.
다만 자손 인스턴스를 직접 형변환을 통해서 참조할 수는 없습니다. 그 이유에 대해서는 여러 검색도 해보고
책도 찾아본 결과... 제가 잠정적으로 내린 결론은
B클래스가 A를 상속받고 있지 않아서입니다. 메모리상의 문제보다는
부모인 B클래스 입장에서 보자면 자손인 A클래스는 상속관계가 없는 녀석입니다.
B클래스는 단순히 피상속관계의 부모클래스이지, A클래스에 대한 이해가 없기 때문입니다.

다만 객체로 생성된 뒤에 A로의 형변환은 메모리의 범위가 가능하기때문에 형변환이 가능해진다고 생각합니다.

ㅎㅎ;;; 이거 참, 쉽게 적는다고 적었는데
제 머릿속으로 이해한 걸 남에게 이해시키려 적었지만 오히려 어렵지않을까 하는 생각이 드네요.

아무쪼록 도움이 되셨음 합니다 ㅎㅎㅎ :)