객체지향개념에서 다형성이란 ‘여러가지 형태를 가질 수 있는 능력'을 의미
자바에서는 한 타입의 참조변수로 여러타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로 구현
→ 조상클래스 타입의 참조 변수로 자손 클래스의 인스턴스를 참조
클래스 TV와 SmartTV는 서로 상속관계에 있다.이 두 클래스가 서로 상속 관계에 있을 경우 조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조할 수 있다.
이 두 클래스가 서로 상속 관계에 있을 경우 조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조할 수 있다.
형변환은 참조 변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향도 미치지 않는다.
단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위(개수)를 조절하는 것뿐이다.
참조변수가 참조하고 있는 인스턴스의 자손타입으로 형변환하는 것은 허용되지 않는다.
컴파일 시에는 참조변수간의 타입만 체크하기 때문에 실행 시 생성될 인스턴스 타입에 대해서는 전혀 알지 못한다. 그래서 컴파일 시에는 문제가 없지만, 실행 시 에러가 발생한다.
TV t = new SmartTV(); // 조상타입의 참조변수로 자손 인스턴스를 참조
인스턴스 타입의 참조변수로 참조와 조상 타입의 참조변수로 참조의 차이
SmartTV s = new SmartTV(); // 자식
TV t = new SmartTV(); // 조상 -> 타입불일치 그러나 명시적 casting으로 인해 접근 가능
둘다 같은 타입의 인스턴스지만 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.
SmartTV s = new TV(); // 컴파일 에러
실제 인스턴스인 TV의 멤버 개수보다 참조변수 s가 사용할 수 있는 멤버 개수가 더 많기 때문에 컴파일 에러가 난다.
실제 인스턴스인 TV의 멤버 개수보다 참조변수 s가 사용할 수 있는 멤버 개수보다 더 많기 때문이다.그래서 이를 허용하지 않는 것이다.
CaptionTV클래스에는 text와 caption()이 정의되어 있으므로 참조변수 s로는 s.caption, s.displayCaption()과 같은 방식으로 s가 참조하고 있는 인스턴스에서 text와 caption()을 사용할 수 있다.
하지만 s가 참조하고 있는 인스턴스는 TV타입이고,TV타입의 인스턴스에는 caption와 displayCaption()이 존재하지 않기 때문에 이를 사용하려고 하면 문제가 생긴다.
그래서 자손타입의 참조변수로 조상타입의 인스턴스를 참조하는 것은
존재하지 않는 멤버를 사용하고자 할 가능성이 있으므로 허용되지 않는 것이다.
참조변수가 사용할 수 있는 메버의 개수는 인스턴스의 멤버 개수보다 같거나 적어야 한다.
클래스는 상속을 통해서 확장될 수는 있어도 축소될 수는 없어서,조상 인스턴스의 멤버 개수는 자손 인스턴스의 멤버 개수보다 항상 적거나 같다.
조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있다.
반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.
기본형 변수와 같이 참조변수도 형변환 가능하다. 사용할 수 잇는 멤버갯수 조절할 수 있다.
업 캐스팅 : 자손타입 → 조상타입 : 형변황 생략 가능
다운 캐스팅 : 자손타입 ← 조상타입 : 형변환 생략 불가
참조변수 간의 형 변환은 () 에 변환하고자 하는 타입의(클래스명)을 적어주면 된다.
형변환 주의해야할 점
형변환은 참조 변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향도 미치지 않는다. 단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위(개수)를 조절하는 것뿐이다.
참조변수가 참조하고 있는 인스턴스의 자손타입으로 형변환하는 것은 허용되지 않는다. 컴파일 시에는 참조변수간의 타입만 체크하기 때문에 실행 시 생성될 인스턴스 타입에 대해서는 전혀 알지 못한다. 그래서 컴파일 시에는 문제가 없지만, 실행 시 에러가 발생한다.
참조변수가 참조 하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용한다.
instanceof를 이용한 연산결과로 true를 얻었다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.
void doWork(Car c) {
if (c instanceof FireEngine){
FireEngine fe = (FireEngine) c;
fe.water();
} else if (c instanceof Ambulance) {
Ambulance a = (Ambulance) c;
s.siren();
}
}
Q 참조변수의 형변환은 왜 하나요?
→ 참조변수를 변경함으로써 사용할 수 있는 멤버 갯수조절 하기 위해서 입니다.
조상클래스에 선언된 멤버변수와 같은 인스턴스를 참조하는 경우 자손타입의 참조변수로 자손 인스턴스를 참조하는 경우는 서로 다른 결과를 얻는다.
맴버변수의 경우 참조 변수의 타입에 따라 달라진다.
장점 1. 다형적 매개변수
Class Product {
int price;
int bonusPoint;
}
class Tv extends Product {}
class Computer extends Product {}
class Audio extends Product {}
class Buyer {
int money = 1000;
int bonusPoint = 0;
}
// 위와 같은 경우에 Tv, Computer, Audio 객체를 모두 매개변수로 받고 싶다면
// 각각을 오버라이딩 할 필요 없이 Product라는 조상 클래스를 이용가 능
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();
// 위의 코드 배열로 처리 결과
Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();
이처럼 조상타입의 참조변수 배열을 사용하면, 공통의 조상을 가진 서로 다른 종류의 객체를 배열로 묶어서 다룰 수 있다. 또는 묶어서 다루고 싶은 객체들의 상속 관계를 따져서 가장 가까운 공통 조상클래스 타입의 참조변수 배열을 생성해서 객체들을 저장 하면 된다.
이 게시물은 자바의 정석 책을 요약한 내용입니다.