다형성은 하나의 코드가 여러 자료형으로 구현되어 실행되는 것을 뜻하며 이는 같은 코드에서 여러 실행 결과가 나올 수 있는 것을 말합니다.
정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나인 다형성은 객체지향 프로그래밍의 유연성, 재활용성, 유지보수성에 기본이 되는 특징입니다.
//1번
//Animal class 생성
class Animal {
public void animalMove() {
System.out.println("동물이 움직입니다");
}
}
class Human extends Animal {
public void animalMove() {
System.out.println("사람이 두발로 걷습니다");
}
}
class Tiger extends Animal{
public void animalMove() {
System.out.println("호랑이가 네발로 뜁니다");
}
}
class Eagle extends Animal{
public void animalMove() {
System.out.println("독수리가 하늘을 납니다");
}
}
//2번 AnimalMove class 생성
public class AnimalMove {
public static void main(String[] args) {
//2번
Animal hAnimal = new Human();
Animal tAnimal = new Tiger();
Animal eAnimal = new Human();
//4번
AnimalMove test = new AnimalMove();
test.moveAnimal(hAnimal);//사람이 두발로 걷습니다
test.moveAnimal(tAnimal);//호랑이가 네발로 뜁니다
test.moveAnimal(eAnimal);//사람이 두발로 걷습니다
}
//3번
public void moveAnimal(Animal animal) {
animal.animalMove();
}
}
다형성을 실습해보기 위해 AnimalMove라는 클래스를 생성합니다.
1번 : Animal 클래스를 만들고 그안에 animalMove라는 메서드를 작성합니다. 그 후 Animal 클래스를 상속하는 3개의 클래스를 더 만들고 그 안에 각각클래스 이름에 맞게 animalMove메서드를 override하여 작성합니다.
2번 : 메인 메서드로 와서 위에서 생성한 3개의 하위클래스를 Animal클래스에 업캐스팅하여 생성합니다.
3번 : AnimalMove 클래스에 moveAnimal 메서드를 작성하고 매개변수를 Animal타입으로 하여 animalMove메서드를 실행하도록 합니다.
4번: moveAnimal 메서드를 실행하기 위해 AnimalMove 인스턴스를 생성하고 각각의 하위 클래스를 매개변수로 하여 moveAnimal을 실행하면 결과 값처럼 같은 메서드에서 다른 결과가 나오는 것을 알 수 있습니다.
이와 같이 하나의 코드에 여러 자료형이 구현되어서 다른 실행이 이루어지는 것이 다형성입니다. 다형성을 이용해서 여러개로 작성될 코드를 하나로 묶어서 효율적으로 코드를 작성할 수 있다는 이점이 있습니다.
ArrayList<Animal> animalList = new ArrayList<Animal>();
animalList.add(hAnimal);
animalList.add(tAnimal);
animalList.add(eAnimal);
for(Animal animal : animalList) {
animal.move();
}
//사람이 두발로 걷습니다
//호랑이가 네발로 뜁니다
//사람이 두발로 걷습니다
ArryList를 사용하여 다형성을 구현해 보기 위해 Anmial을 자료형으로하는 animaList를 만듭니다.
.add 메서드로 각 클래스를 animalList에 넣고 향상된 for문을 사용해 하나씩 돌아가며 .move()메소드를 사용하게 하면 위의 예제와 같은 결과를 얻을 수 있습니다. 이때의 move는 각 인스턴스의 move가 사용된 것입니다.
다형성은 다양한 개념이 결합되어 구현됩니다. 한 클래스의 기능을 구체적으로 확장한 상속, 상속관계에 의해 묵시적으로 일어나는 의한 업캐스팅, 상속된 메서드를 재정의하는 오버라이딩, 오버라이딩 된 메서드는 업캐스팅 하더라도 인스턴스의 메서드로 실행한다는 가상함수 그리고 이 모든 것을 통해 하나의 코드로 다양한 자료형을 실행할 수 있는 다형성을 한 맥락에서 이해하고 활용할수 있게 되는 것을 목표로 해야합니다.
다형성을 이용하여 다양한 여러 클래스를 하나의 자료형(상위 클래스)으로 선언하거나 형변환 하여 각 클래스가 동일한 메서드를 오버라이딩 한 경우, 하나의 코드가 다양한 구현을 실행 할 수 있습니다.
다형성을 통해서 유사한 클래스가 추가되는 경우 유지보수에 용이하고 각 자료형 마다 다른 메서드를 호출하지 않으므로 코드에서 많은 if문이 사라지는 장점이 있습니다.
public class GoldCustomer extends Customer {
public double salesRatio;
public GoldCustomer() {
bonusRatio = 0.02;
salesRatio = 0.1;
customerGrade = "Gold";
}
@Override
public int calPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price * salesRatio);
}
VipCustomer에 이어 GoldCustomer를 추가하려고 할때 상속과 오버라이딩을 통해 손쉽게 추가할 수 있습니다.
이후 Customer 클래스를 통해 하위클래스들을 쉽게 관리할 수 있다는 장점이 있습니다.
상속을 언제 사용할까?
IS - A관계는 일반적인(general)개념과 구체적인(specific)개념과의 관계를 뜻합니다. 한 클래스와 다른 클래스가 IS-A관계 일 때 상속을 사용합니다.
상위 클래스는 일반적인 개념 클래스이고(예 포유류) 하위 클래스는 구체적인 개념 클래스(예: 사람, 원숭이, 고래..)에 속합니다.
클래스간에 상속관계가 만들어지면 클래스간에 관계가 타이트해져서 상위 클래스에 변화를 주면 하위클래스에 영향을 주게 됩니다. 그렇기에 단순히 코드를 재사용하는 목적으로 상속을 사용하지는 않습니다.
반면에 HAS-A관계는 한 클래스가 다른 클래스를 소유한 관계로 코드 재사용의 한 방법입니다.
만약 우리가 ArrayList클래스를 사용하고 싶다면 ArrayList extends하여 상속해서 사용 하는 것이 아닌 인스턴스를 하나 생성해서 사용하는 것 같이 필요한 코드를 재사용을 위해선 생성해서 사용하면 됩니다.