먼저, 다형성이란 ‘many form’ 즉, 많은 형태를 의미한다. 이는 자바의 중요한 OOP 개념 중 하나이다.
다형성은 상속으로 인한 서로 관련된 많은 클래스들이 있을 때 발생한다.
상속을 통해 Attribute와 Method를 다른 클래스에서 사용할 수 있는데 다형성은 이러한 메서드들을 서로 다르게 동작할 수 있도록 만든다. 이와 같은 점은 코드의 재활용성을 높이는 데 이용된다.
Java의 다형성에는 두 가지 타입이 있다. (중요!)
먼저, 정적 다형성(혹은 컴파일 타임 다형성)에는 오버로딩이라는 단어를 알아야 한다.
오버로딩이란, 다양한 메서드를 동일한 이름으로 사용할 수 있다.
오버로딩을 사용하기 위해선 조건이 붙는다.
다음 코드를 보자.
// example) static polymorphism
public class Main {
public static void main(String args[]){
Method addMet = new Method();
System.out.println(addMet.add(1, 2));
System.out.println(addMet.add(1.5, 2.0));
System.out.println(addMet.add(1, 2.0));
}
}
public class Method {
public int add(int x, int y){
return x+y;
}
public int add(int x, double y){
return x+(int)y;
}
public double add(double x, double y){
return x+y;
}
}
위 코드를 봤을 때, 서로 같은 이름의 메서드들이 세 가지 조건에 따라서 에러 없이 잘 작동하는 것을 알 수 있다.
각 메서드들의 서로 다른 Signature는 컴파일러가 어떤 메서드가 호출됐는지 식별할 수 있게 하고, 이것을 해당하는 메서드 호출에 바인딩 할 수 있게 해준다.
이러한 접근 법을 Static Binding 혹은 Static Polymorphism 이라고 한다.
동적 다형성의 경우 컴파일러가 실행방법을 결정하게 하지 않는다. JVM은 런타임에 이를 수행해야 한다. 이렇게 말하면 헷갈리니 좀 더 들여다 보자.
상속에서 서브클래슨느 슈퍼클래스의 메서드를 오버라이드할 수 있다. 오버라이드란 상속받은 메서드를 다른 방식으로 수행되도록 대체하는 것을 말한다.
코드를 보자.
// example ) Overriding
class Main {
public static void main(String args[]){
Animal myAnimal = new Animal();
Dog myDog = new Dog();
Bird myBird = new Bird();
Cat myCat = new Cat();
myAnimal.eat();
myDog.eat();
myBird.eat();
myCat.eat();
}
}
class Animal {
public void eat(){
System.out.println("Animal eat..");
}
}
class Dog extends Animal {
@Override
public void eat(){
System.out.println("Dog eat..");
}
}
class Bird extends Animal {
@Override
public void eat(){
System.out.println("Bird eat..");
}
}
class Cat extends Animal {
@Override
public void eat(){
System.out.println("Cat eat..");
}
}
다음과 같은 결과로 나타난다.

이렇게 부모 클래스에서 구현한 메서드를 자식 클래스에서 다른 동작을 하도록 다시 만드는 것을 오버라이딩이라고 한다. 또한, 이렇게 런타임에 결정되는 다형성을 동적 다형성이라고 한다.