다형성이란?
다형성이란 하나의 타입에 여러 객체를 대입할 수 있는 성질을 말합니다.
다형성의 장점
다형성을 활용하면 기능을 확장하거나, 객체를 변경해야 할 때 타입 변경 없이 객체 주입만으로 수정이 일어나게 할 수 있습니다.
또한 상속을 사용한다면 중복되는 코드까지 제거할 수 있으므로 더 객체 지향 설계에 가까워질 수 있습니다.
다형성을 왜 사용하는가?
Polymorphism allows us to perform a single action in different ways.
(ref. https://www.w3schools.com/java/java_polymorphism.asp)
다형성은 하나의 행동을 여러 방식으로 수행할 수 있게 해줍니다.
다형성을 구현하는 방법
다형성을 구현하는 방법에는 대표적으로 "오버로딩", "오버라이딩" 등이 있습니다.
오버로딩(Overloading)
오버로딩이란? 클래스가 인자의 개수나 자료형이 다르나 동일한 이름을 가진 여러 개의 메서드를 가지는 것
오버로딩의 장점 : 프로그램의 가독성을 향상시킵니다.
메서드 오버로딩의 구현 방법 : 인자의 개수 혹은 자료형을 다르게 함으로써 메서드 오버로딩을 구현할 수 있습니다.
오버로딩은 하나의 클래스에서 같은 이름의 메서드를 여러 개 가질 수 있게 해줍니다.
단, 메서드 인자들은 달라야 합니다. (반환 타입은 같아도 되고 달라도 됩니다.)
인자들의 타입이나 개수가 다르면 메서드 이름이 같더라도 어떤 메서드를 호출할 지 컴파일러가 알 수 있기 때문입니다
예시) Adder class 에 정의되어 있는 add 함수
add 함수는 아래와 같이 매개변수의 개수만 다른 여러 개의 메서드가 정의되어 있습니다.
매개변수로 정수 2개 혹은 3개를 넣을 때 모두 add 라는 메서드를 호출하여 정수들의 총합을 계산하는 기능을 수행합니다.
class Adder{
static int add(int a, int b) {
return a + b;
}
// 인자의 개수가 다른 경우
static int add(int a, int b, int c) {
return a + b + c;
}
// 인자의 자료형이 다른 경우
static double add(double a, double b) {
return a + b;
}
}
class TestOverloading1 {
public static void main(String[] args) {
System.out.println(Adder.add(11,11));
System.out.println(Adder.add(11,11,11));
System.out.println(Adder.add(12.3,12.6));
}
}
오버로딩은 여러 종류의 타입을 받아들여 결국엔 같은 기능을 하도록 만들기 위한 작업입니다.
메서드를 동적으로 호출할 수 있으니 다형성이라고 할 수 있습니다.
오버라이딩(Overriding)
오버라이딩은 슈퍼 클래스를 상속받은 서브 클래스에서 슈퍼 클래스의 (추상) 메서드를 같은 이름, 같은 반환값, 같은 인자로 메서드 내의 로직들을 새롭게 정의하는 것을 말합니다. 쉽게 말해서, 상위 클래스의 메서드를 하위 클래스에서 재정의하는 것을 말합니다.
이를 이용하면 하나의 슈퍼 클래스를 상속받는 여러 서브 클래스들이 같은 이름에 다른 기능을 하는 메서드를 정의하고 사용하게 해줍니다.
마치 키패드라는 형태를 가졌지만 '1' 키를 누르면 1이 화면에 표시되고, 'ㄱ' 키를 누르면 ㄱ이 화면에 표시되는 것처럼 말입니다.
예시)
추상 클래스 Figure 에는 하위 클래스에서 오버라이드 해야 할 메서드가 정의되어 있습니다.
public abstract class Figure {
protected int dot;
protected int area;
public Figure(final int dot, final int area) {
this.dot = dot;
this.area = area;
}
public abstract void display();
// getter
}
Figure 를 상속받은 하위 클래스인 Triangle 객체는 해당 객체에 맞는 기능을 구현합니다.
public class Triangle extends Figure {
public Triangle(final int dot, final int area) {
super(dot, area);
}
@Override
public void display() {
System.out.println("넓이가 %d인 삼각형입니다.", area);
}
}
만약 사각형 객체를 추가하고 싶다면, 같은 방식으로 Figure를 상속받되 메서드 오버라이딩으로 메서드 부분에서 사각형에 맞는 display 메서드를 구현해주면 됩니다.
public static void main(String[] args) {
Figure figure = new Triangle(3, 10); // 도형 객체 추가 또는 변경 시 이 부분만 수정
for (int i = 0; i < figure.getDot(); i++) {
figure.display();
}
}
만약 여기서 다형성을 사용하지 않고 도형 객체를 추가하는 로직을 생각해 본다면 다음과 같이 if-else 분기가 늘어나게 될 것입니다.
public static void main(String[] args) {
int dot = SCANNER.nextInt();
if (dot == 3) {
Triangle triangle = new Triangle(3, 10);
for (int i = 0; i < triangle.getDot(); i++) {
triangle.display();
}
} else if (dot == 4) {
Rectangle rectangle = new Rectangle(4, 20);
for (int i = 0; i < rectangle.getDot(); i++) {
rectangle.display();
}
}
// ...
}
여기까지 오버라이딩 방식으로 다형성을 구현하는 방법을 살펴보았습니다.
오버라이딩 다형성 방식을 잘 활용하면 기능의 확장과 객체의 수정에 유연한 구조를 가져갈 수 있습니다.
정리
다형성은 하나의 타입에 여러 객체를 대입할 수 있는 성질입니다.
다형성을 구현하기 위해서는 여러 객체들 중 공통 특성으로 타입을 추상화하고 그것을 상속(인터페이스라면 구현)해야 합니다.
다형성은 변화에 유연한 소프트웨어를 만들기 위해 없어서는 안 될 개념입니다.
출처
https://tecoble.techcourse.co.kr/post/2020-10-27-polymorphism/
https://www.javatpoint.com/method-overloading-in-java