상위클래스인 Employee type의 reference 변수(e1, e2)는 Manager와 CSR 즉, 하위클래스의 Reference를 저장할 수 있다.
public class Employee{
//class_code_block
}
public class Manager extends Employee{
//class_code_block
}
public class CSR extends Employee{
//class_code_block
}
public class PolymorphicExample{
public static void main(String[] args){
Employee e1 = new Manager();
Employee e2 = new CSR();
}
}
재정의된 메서드에 대한 호출이 컴파일 타임이 아닌 런타임에 해결되는 프로세스 또는 메커니즘이다. 런타임 다형성(Runtime Polymorphism) 또는 동적 메서드 디스패티(Dynamic Method Dispatch)라고도 한다.
Java의 다형성의 유형
동적 다형성의 속성
- 런타임에 실행할 메서드를 결정한다.
- 동적 바인딩을 통해 처리될 수 있다.
- 서로 다른 클래스 사이에서 발행한다.
- 동적 다형성을 위해 하위 클래스 객체가 상위 클래스 객체에 할당되는 경우에 필요하다.
- 상속관계에서 수행된다.
class Animal{
void eat(){System.out.println("먹기");}
}
class Dog extends Animal{
void eat(){System.out.println("과일 먹기");}
}
class BabyDog extends Dog{
void eat(){System.out.println("우유 마시기");}
public static void main(String[] args){
//재정의된 메서드가 호출된다.
Animal a1, a2, a3;
a1 = new Animal();
a2 = new Dog();
a3 = new BabyDog();
a1.eat();
a2.eat();
a3.eat();
}
}
[결과]
먹기
과일 먹기
우유 마시기
//Dog의 eat()메서드를 오버라이드하지 않았을 경우
public class BabyDogEx2 extends Dog{
public static void main(String[] args){
Animal a = new BabyDogEx2();
a.eat();
}
}
[결과]
과일 먹기
class Bike{
int speedlimit = 90;
}
class Honda extends Bike{
int speedlimit = 150;
public static void main(String[] args){
Bike obj = new Honda();
System.out.println(obj.speedlimit); //90
}
}
MyDate[] dates = new MyDate[2];
dates[0] = new MyDate(22,12,1964);
dates[1] = new MyDate(22,7,1964);
Employee[] staff = new Employee[1024];
staff[0] = new Manager();
staff[1] = new Employee();
staff[2] = new Engineer();
public clas Animal{
public static void main(String[] args){
Pet myPets[] = new Pet[4];
myPets[0] = new Pet();
myPets[1] = new Cat();
myPets[2] = new Duck();
myPets[3] = new Dog();
for(int i=0; i<myPets.length; i++){
myPets[i].speak();
}
}
}
[결과]
애완동물 말하기
야옹
꽥꽥
멍멍
Argument type을 상위클래스 타입으로 선언하게 되면 하위클래스들의 타입으로 전달할 수 있다. (상속의 is a 관계 - Manager is an Employee)
//In the Employee class
public TaxRate findTaxRate(Employee e){}
//Meanwhile, elsewhere in the application class
Manager m = new Manager();
...
TaxRate t = findTaxRate(m);
public void doSomething(Employee e){
if(e instanceof Manager){
//Manager를 위한 처리
System.out.println("Manager instance");
}else if(e instanceof Engineer){
//Engineer를 위한 처리
System.out.println("Engineer instance");
}else{
//그 외의 처리
}
}
public static void main(String[] args){
InstanceOfExam i = new InstanceOfExamp();
Employee emp = new Manager();
Employee eng = new Engineer();
i.doSomething(emp);
i.doComething(eng);
}
[결과]
Manager instance
Engineer instance
instanceof 연산자로 다운캐스팅이 가능한지 확인 후 다운캐스팅을 수행하여 ClassCastException 예외를 방지한다.
class Animal{}
class Dog extends Animal{
static void method(Animal a){
if(a instanceof Dog){
Dog d = (Dog)a; //downcasting
System.out.println("다운캐스팅 가능");
}
}
public static void main(String[] args){
Animal a = new Dog();
Dog.method(a);
}
}
Pet pet = new Pet();
Dog dog1 = new Dog();
Dog dog2 = null;
dog1.speak();
//하위클래스 -> 상위클래스로 업캐스팅(생략가능)
pet = dog1;
//상위클래스 -> 하위클래스로 다운캐스팅
dog2 = (Dog)pet;
dog2.speak();
상속을 통해 다형성을 구현했던 Pet 예제를 abstract class와 method를 통해 구현
abstract public class Pet{
public abstract void speak();
}
public class Dog extends Pet{
@Override
public void speak(){
System.out.println("멍멍");
}
}
public class Cat extends Pet{
@Override
public void speak(){
System.out.println("야옹");
}
}
public class Duck extends Pet{
@Override
public void speak(){
System.out.println("꽥꽥");
}
}
public class AbstractClassTest{
public static void main(String[] args){
Pet myPets[] = new Pet[4];
myPets[0] = new Duck();
myPets[1] = new Cat();
myPets[2] = new Duck();
myPets[3] = new Dog();
for(int i=0; i<myPets.length; i++){
myPets[i].speak();
}
}
}
[결과]
꽥꽥
야옹
꽥꽥
멍멍
public abstract class AbstractDisplay{
public abstract void open();
public abstract void print();
public abstract void close();
//Template method - 알고리즘 구조(처리과정)
public final void display(){
open();
for(int i=0; i<5; i++){
print();
}
close();
System.out.println();
}
}
public class CharDisplay extends AbstractDisplay{
private char ch;
public CharDisplay(char ch){
this.ch = ch;
}
@Override
public abstract void open(){
System.out.println("<<");
}
@Override
public abstract void print(){
System.out.println(ch);
}
@Override
public abstract void close(){
System.out.println(">>");
}
public static void main(String[] args){
CharDisplay ch = new CharDisplay('@');
ch.display();
}
}
[결과]
<<@@@@@>>