객체지향에서 다형성이라고 하면 오버라이딩(overriding)과 오버로딩(overloading)이라고 할 수 있다.
재정의
이다.중복정의
이다.예제 코드는 다음과 같다.
Animal.java
package polymorphism01;
public Class Animal {
public String name;
public void showName(){
System.out.printf("안녕 나는 %s야. 반가워\n", name);
}
}
Penguin.java
package polymorphism01;
public Class Penguin extends Animal {
public String habitat;
public void showHabitat(){
System.out.printf("%s는 %s에 살아\n", name, habitat);
}
// 오버라이딩 - 재정의 : 상위 클래스의 메서드와 같은 메서드 이름, 같은 인자 리스트
public void showName() {
System.out.println("어머 내 이름은 알아서 뭐하게요?");
}
// 오버로딩 - 중복정의 : 같은 메서드 이름, 다른 인자 리스트
public void showName(String yourName) {
System.out.println("%s 안녕, 나는 %s라고 해\n", yourname, name);
}
}
Driver.java
package polymorphism01;
public Class Driver {
public static void main(String[] args) {
Penguin pororo = new Penguin();
pororo.name = "뽀로로";
pororo.habitat = "남극";
pororo.showName(); // 어머 내 이름은 알아서 뭐하게요?
pororo.showName("초보람보"); // 초보람보 안녕, 나는 뽀로로라고 해
pororo.showHabitat(); // 뽀로로는 남극에 살아
Animal pingu = new Penguin();
pingu.name = "핑구";
pingu.showName(); // 어머 내 이름은 알아서 뭐하게요?
}
}
바로 위의 Driver.java 클래스를 보자. Driver.java에서 Penguin pororo = new Penguin(); 을 실행한 후의 T 메모리 스냅샷은 다음과 같다.
여기에서 주목할 것은 Penguin 클래스가 상위 클래스인 Animal 클래스의 showName() 메서드를 오버라이딩(재정의)했다는 것과 showName(yourName:String) 메서드를 오버로딩(중복정의)했다는 것이다.
Animal pingu = new Penguin(); 을 실행한 후의 T 메모리 스냅샷은 다음과 같다.
pingu 객체 참조 변수는 타입이 Animal 타입이다. 그럼에도 불구하고 그림에서 보면 Animal 객체의 showName()은 Penguin 객체의 showName()에 의해 가려져 있다. 따라서 pingu.showName() 메서드를 실행하면 Animal 객체에 정의된 showName() 메서드가 아닌 Penguin 객체에 의해 재정의된 showName() 메서드가 실행된다.
상위 클래스 타입의 객체 참조 변수를 사용하더라도 하위 클래스에서 오버라이딩(재정의)한 메서드가 호출된다는 사실을 꼭 기억하자.
오버로딩을 사용하면 함수명 하나를 가지고 인자목록만 달리하면 되기 때문에 사용하기 편리하다. 특히 자바 5에서 추가된 제네릭
을 사용하면 하나의 함수만 구현해도 다수의 함수를 구현한 효과를 낼 수 있다. 다형성에 대해 사용 편의성이라고 정의한 이유는 바로 이 때문이다.
오버라이딩의 경우에도 하위 클래스가 재정의한 메서드를 알아서 호출해 줌으로써 형변환이나 instanceOf 연산자를 써서 하위 클래스가 무엇인지 신경 쓰지 않아도 된다
. 상위 클래스 타입의 객체 참조 변수에서 하위 클래스가 오버라이딩한 메서드를 자동으로 호출해 줌으러써 깔끔한 코드를 유지할 수 있게 된다.
Driver.java
Class Driver {
public static void main(String[] args) {
동물[] 동물들 = new 동물[5];
동물들[0] = new 쥐();
동물들[1] = new 고양이();
동물들[2] = new 강아지();
동물들[3] = new 송아지();
for(int i = 0; i < 동물들.length; i++) {
동물들[i].울어보세요();
}
}
}
위와 같은 소스 코드를 생각해보자. 상위 클래스인 동물 클래스에 울어보세요()라는 메서드를 정의해두고 하위 클래스인 쥐, 고양이, 강아지, 송아지 클래스에서 각각 울어보세요() 메서드를 오버라이딩했다고 가정해보자. 실행 결과는 각 동물들이 하위 클래스 타입에 맞게 울게 된다는 것이다. 실행 결과는 다음과 같을 것이다.
나는 쥐! 찍! 찍!
나는 고양이! 야옹! 야옹!
나는 강아지! 멍! 멍!
나는 송아지! 음메! 음메!
오버라이딩을 통한 메서드 재정의, 오버로딩을 통한 메서드 중복 정의를 통해 다형성을 제공하고 다형성이 개발자가 프로그램을 작성할 때 사용편의성을 준다.
참고