
다형성이란, 같은 자료형에 여러 가지 객체를 대입해 다양한 결과를 얻어내는 성질을 의미한다. 자주 쓰이는 케이스로 부모 클래스에 자식클래스를 넣을 수 있는 것을 말한다.
여기서 중요한 사실 중 하나는 만일 어떤 값을 extends or implements 했을 때, 오버라이딩을 하지 않는다면, 자식을 부모타입에 넣더라도 해당 메서드를 사용할 수 없다는 것이다.
결국 어떤 임의의 A 클래스를 상속받은 B, C, D, E 클래스가 있을 때, 해당 B, C, D, E 모두 A 클래스 타입에 할당할 수 있고 할당한 후에 사용할 수 있는 함수는 오버라이딩을 한 함수이다. 즉, Interface 또는 Class 를 implements, extends 하더라도 해당 함수를 오버라이딩 하지 않으면 다형성을 이용하더라도 대입한 클래스의 메서드를 사용할 수 없다. 이는 추상 클래스에서도 동일하다.
public class A_Class {
public String work() {
return "work A";
}
}
A_Class 가 있고
public class B_Class extends A_Class {
// 아래 @Overring 애노테이션은 오버라이딩에 관련된 오류를 미리 잡아줌
@Overring
public String work() {
return "work B";
}
public String run() {
return "run B";
}
}
A_Class를 상속받는 B_Class가 있다고 가정해보자
public class Main {
public static void main(String[] args) {
B_Class instance = new B_Class();
System.out.println(instance.work());
// work B
System.out.println(instance.run());
// run B
}
}
우리는 보통 위처럼 코드를 작성한다. 이는 B_Class 타입 변수에 new 연산자를 사용하여 B_Class의 인스턴스를 넣는 작업이다.
이렇게 되면, instance 인스턴스를 사용하여 B_Class가 가진 메서드들을 사용할 수 있다.
하지만, 다형성을 알게되면 아래처럼 코드를 작성한다.
public class Main {
public static void main(String[] args) {
A_Class instance = new B_Class();
System.out.println(instance.work());
// work B
System.out.println(instance.run());
// 에러 발생 A_Class 의 메서드를 오버라이딩 하지 않았기 때문
}
}
A_Class를 상속받은 B_Class의 인스턴스를 A_Class 타입의 변수에 넣을 수 있다. 타입은 A_Class지만, 그 내부에는 B_Class의 인스턴스가 들어있다. 출력값은 오버라이딩 한 “work B”가 출력된다.
위에서 말했듯이 run 메서드는 A_Class에 존재하는 메서드를 상속 또는 구현한게 아니라 클래스 자체에 정의한 메서드이므로 사용할 수 없다(A_Class는 run에 대해 모르기 때문).
만일 run 메서드를 사용하고 싶다면 B_Class 타입 변수에 B_Class 인스턴스를 할당해야 한다. 이를 테스트 하기 위해 상속과 구현을 동시에 해보자.
public interface A_Interface {
public String run();
}
먼저 A_Interface를 정의하고,
public class B_Class extends A_Class implements A_Interface {
@Override
public String run() {
return "run B";
}
}
B_Class를 수정하여 기존의 run 메서드를 구현한다.
public class Main {
public static void main(String[] args) {
A_Class instance_class = new B_Class();
A_Interface instance_interface = new B_Class();
System.out.println(instance_class.work());
// work B
System.out.println(instance_interface.run());
// run B
}
}
메인에서는 각각 A_Class 타입의 변수와 A_Interface 타입의 변수에 B 클래스 인스턴스를 넣음으로써 각 메서드를 호출할 수 있다.
위와 같은 상속, 구현의 기능을 이용할 수 있는건 모두 다형성 덕분이다. 다형성을 이용해 클라이언트 코드에서 직접적으로 인스턴스를 생성하지 않고 외부의 설정자에서 인스턴스를 주입 해준다는 개념이 바로 DI, 의존성 주입인 것이다.
다형성은 Java와 Spring에서 가장 중요한 개념이므로 충분히 숙지해야 할 필요가 있다.
Java 중요 개념 5가지
https://bytheprogramer-fortheprogramer.tistory.com/6
자바 중요개념 - Polymorphism
https://bytheprogramer-fortheprogramer.tistory.com/7