하나의 인스턴스가 여러 가지 타입을 가질 수 있는 것을 의미한다. 그렇기 때문에 하나의 타입으로 여러 타입의 인스턴스를 처리할 수 있기도 하고, 하나의 메소드 호출로 개체별로 각기 다른 방법으로 동작하게 할 수도 있다.
다형성은 객체지향 프로그램의 4대 특징 (추상화, 상속, 다형성, 캡슐화) 중 하나이며, 객체지향 프로그래밍의 꽃이라고 불리울 정도로 활용성이 높고 장점이 많다.
Animal[] arr = new Animal[5];
arr[0] = new Dog();
arr[1] = new Cat();
arr[2] = new Rabbit();
arr[3] = new Pig();
arr[4] = new Mouse();
for(Animal animal : arr) {
animal.cry();
}
arr[0].runDog();
arr[1].runCat();
arr[2].runRabbit();
arr[3].runPig();
arr[4].runMouse();
// 모든 메세지를 다 기억하고 사용해야 한다.
for(Animal animal : arr) {
animal.run();
}
// 관리해야 하는 메세지 수가 줄어든다.
run(new Dog());
run(new Cat());
// 새로운 동물 추가 시 run 메소드를 더 만들지 않아도 된다.
public void run(Animal animal) {
animal.run();
}
// 한식을 먹을 경우
public void eat(한식) {
한식.먹어라();
}
// 음식이 양식으로 바뀌는 경우
public void eat(양식) {
양식.먹어라();
}
// 한식, 양식 둘 다 가능하도록, 어느 한 쪽을 의지하지 않게 만듦
public void eat(음식) {
음식.먹어라();
}
Animal animal = new Tiger();
animal.cry();
//실제로 동작하는 것은 호랑이 인스턴스이다.
// 업캐스팅(up-casting)
// 명시적
Animal animal = (animal) new Tiger();
//묵시적
Animal animal = new Tiger();
// 다운캐스팅(down-casting) : 묵시적 불가, 명시적으로만 가능
// 컴파일 시 animal의 type은 animal이기 때문에 Tiger 클래스의 멤버에 접근이 불가능하다.
// 멤버가 존재하는 타입으로 다운캐스팅 해 주어야 한다.
((Tiger) aniaml).bite();
원래 인스턴스의 형이 맞는지 여부를 체크하는 키워드
맞으면 true 아니면 false를 반환함
클래스 형변환의 경우 런타임 시 존재하는 타입과 형변환하려는 타입이 일치하지 않는 경우 ClassCastException이 발생한다. 그렇기에 조금 더 런타임 시 안전한 형변환을 하기 위해 instanceof 연산자를 이용할 수 있다.
instanceof 연산자는 레퍼런스 변수가 실제로 클래스 타입의 인스턴스인지 확인하여 true or false를 반환한다.
if ( animal instanceof Human) {
Human human = (Human)animal;
human.readBooks();
} else if( animal instanceof Tiger) {
Tiger tiger = (Tiger)animal;
tiger.hunting();
} else if( animal instanceof Eagle) {
Eagle eagle = (Eagle)animal;
eagle.flying();
} else {
System.out.println("error");
}