5. 다형성(polymorphism)
- 조상의 참조변수로 자손의 객체를 사용하는 것
다형성이 가장 중요함!
상속관계가 맺어졌을떄만
조상에게만 해당
조상이 자손의 클래스를 참조...
A가 조상이고 B가 자손인 경우
A a = new B(); << 가능, B()에는 조상, 자식 다있음
B b = new A(); << 불가능, A()에는 조상꺼 밖에 없음
따라서
Object obj = new A(); 당연히 가능!! 오브젝트는 모든 클래스 가능!
(리턴타입이 무엇인지 잘모르고 예측이 어려울때 모든 자바 클래스의 조상인 Object로 받아 사용한다. 또는 대입되는, 리턴되는 타입이 무엇인지 모를때 모든 것을 받을 수 있는 Object 클래스를 사용한다. )
ex) int add(Object obj) {~~} << 모든 타입을 받겠다는 의미
즉, 다형성은 오버라이딩된 자손 클래스의 메서드를 쓰기위한 방법!!
5.1 다형성이란?
- 여러 가지 형태를 가질 수 있는 능력
- 하나의 참조변수로 여러 타입의 갹체를 참조할 수 있다는 것
- 즉, 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있다는 것이 다형성.
- 조상타입의 참조변수로 자손타입의 인스턴스를 참조할수 있지만, 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.
A가 조상이고 B가 자손인 경우
A a = new B(); << 가능, B()에는 조상, 자식 다있음
B b = new A(); << 불가능, A()에는 조상꺼 밖에 없음
class A
{
int x = 10;
void add()
{
System.out.println("자손");
}
}
class B extends A
{
int x = 20;
void add()
{
System.out.println("자손");
}
void test(){}
}
class Test
{
public static void main(String[] args)
{
A a = new B();
a.add();
//조상 클래스가 자식 클래스의 오버라이딩된 메서드를 사용하기 위함
//자손의 test()는 사용불가능
}
}
class Product
{
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수
Product(int price) {
this.price = price;
bonusPoint =(int)(price/10.0); // 보너스점수는 제품가격의 10%
}
}
class Tv extends Product {
Tv() {// 조상클래스의 생성자 Product(int price)를 호출한다.
super(100); // Tv의 가격을 100만원으로 한다.
}
public String toString() { // Object클래스의 toString()을 오버라이딩한다.
return "Tv"; //그냥 참조변수만 호출하면 toString이 호출된다!!
}
}
class Computer extends Product {
Computer() {
super(200);
}
public String toString() {
return "Computer";
}
}
class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스점수
void buy(Product p) { //다형성 : 자손인 컴퓨터와 TV가 들어갈 예정
if(money < p.price) {
System.out.println("잔액이 부족하여 물건을 살수 없습니다.");
return;
}
money -= p.price; // 가진 돈에서 구입한 제품의 가격을 뺀다.
bonusPoint += p.bonusPoint; // 제품의 보너스 점수를 추가한다.
System.out.println(p + "을/를 구입하셨습니다.");
//그냥 참조변수만 호출하면 toString이 호출된다!!
}
}
class PolyArgumentTest{
public static void main(String args[]) {
Buyer b = new Buyer();
Tv tv = new Tv();
Computer com = new Computer();
b.buy(tv);
b.buy(com);
System.out.println("현재 남은 돈은 " + b.money + "만원입니다.");
System.out.println("현재 보너스점수는 " + b.bonusPoint + "점입니다.");
}
}
5.2 참조변수의 형변환
- 서로 상속관계에 있는 타입간의 형변환만 가능하다.- 자손 타입에서 조상타입으로 형변환하는 경우, 형변환 생략가능
자손타입->조상타입(up-casting) : 형변환 생략 가능
조상타입->자손타입(down-casting) : 형변환 생략 불가
약간 비슷한 개념으로 보면 double형 5.7을 int 에 삽입시 5는 사용가능하고 0.7은 버려지는 것과 비슷
class CastingTest1
{
public static void main(String[] args)
{
Car car = null;
Car car2 = null;
FireEngine fe = new FireEngine();
FireEngine fe2 = null;
fe.water();
car = fe; // car = (Car)fe1;에서 형변환이 생략된 형태이다.
// car.water(); // 컴파일 에러!!! Car타입의 참조변수로는 water()를 참조할수 없당.
fe2 = (FireEngine)car; // 자손타입 <- 조상타입
// 의미상 조상이 자손보다 더 큰 데이터 타입이라고 볼수있다.(크기로 보면 자식이 더 크지만..)
fe2.water();
// 주로 Object 클래스에 넘겨서 한다..
}
}
class Car
{
String color;
int door;
void drive()
{
System.out.println("drive");
}
void stop()
{
System.out.println("stop");
}
}
class FireEngine extends Car
{
void water()
{
System.out.println("water");
}
}
5.3 instanceof 연산자
- 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용
- 이항연산자이며 피연산자는 참조형 변수와 타입, 논리형을 리턴함
- instanceof의 연산 결과 true이면, 해당 타입으로 형변환이 가능하다.
5.4 참조변수와 인스턴스변수의 연결
- 맴버변수가 중복정의된 경우, 참조변수의 타입에 따라 연결되는 맴버변수가 달라진다.(참조변수타입에 영향받음)
- 메서드가 중복 적의된 경우, 참조변수의 타입에 관계없이 항상 실제 인스턴스의 타입에 정의된 메서드가 호출된다.(참조변수타입에 영향받지 않음)
5.5 매개변수의 다형성
- 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.