1. 다형성 개요
1. 다형성의 정의 및 사용 이유
1-1. 다형성(Polymorphism)이란?
💡 하나의 인스턴스가 여러 가지 타입을 가질 수 있는 것을 의미한다. 그렇기 때문에 하나의 타입으로 여러 타입의 인스턴스를 처리할 수 있기도 하고, 하나의 메소드 호출로 객체별로 각기 다른 방법으로 동작하게 할 수 도 있다.
다형성은 객체지향 프로그래밍의 3대 특징(캡슐화, 상속, 다형성) 중 하나이며, 객체지향 프로그래밍의 꽃이라고 불리울 정도로 활용성이 높고 장점이 많다.

- 자식으로 내려갈수록 많은 클래스를 가지고 있다.

1-2. 다형성의 장점
A. 여러 타입의 객체를 하나의 타입으로 관리할 수 있기 때문에 유지보수성과 생산성이 증가된다.
B. 상속을 기반으로 한 기술이기 때문에 상속관계에 있는 모든 객체는 동일한 메세지를 수신할 수 있다. 이런 동일한 메세지를 수신받아 처리하는 내용을 객체별로 다르게 할 수 있다는 장점을 가지고 있다. (다양한 기능을 사용하는데 있어서 관리해야 하는 메세지 종류가 줄어들게 된다.)
C. 확장성이 좋은 코드를 작성할 수 있다.
D. 결합도를 낮춰서 유지보수성을 증가시킬 수 있다.
1-3. 동적 바인딩
💡 컴파일 당시에는 해당 타입의 메소드와 연결되어 있다가 런타임 시 실제 해당 인스턴스가 메소드(오버라이딩 한 메소드)로 바인딩이 바뀌어 동작하는 것을 의미한다.
- 동적 바인딩의 성립 조건
상속 관계를 가지는 부모 자식 클래스에 오버라이딩 된 메소드를 호출해야 한다.

1-4. 업캐스팅과 다운캐스팅
💡 상속관계에 있지만 오버라이딩 한 것이 아닌 후손 객체가 고유하게 가지는 확장된 기능을 사용하기 위해서는 실제 인스턴스의 타입으로 다운캐스팅(클래스 형변환)을 해 주어야 한다.
클래스 형변환은 상위 타입 형변환(up-casting)과 하위 타입 형변환(down-casting)이 있다. 상위 타입 형변환의 경우 묵시적으로 일어나며, 하위 타입 형변환은 명시적으로 작성해야 한다.
1-5. Instanceof 연산자
💡 클래스 형변환의 경우 런타임시 존재하는 타입과 형변환하려는 타입이 일치하지 않는 경우 ClassCastException이 발생한다. 그렇기에 조금 더 런타임 시 안전한 형변환을 하기 위해 instanceof 연산자를 이용할 수 있다. instanceof 연산자는 레퍼런스 변수가 실제로 어떤 클래스 타입의 인스턴스인지 확인하여 true or false를 반환한다.
If(레퍼런스 변수 instanceof 클래스 타입) {
}
Car car = new Sonata();
if(car instanceof Sonata) {
((Sonata) car).moveSonata();
} else if(car instanceof Avante) {
((Avante) car).moveAvante();
} else if(car instanceof Grandure) {
((Grandure) car).moveGrandure();
}
2. 추상 클래스와 인터페이스
1. 추상 클래스
1-1. 추상 클래스(Abstract Class)란?
💡 **추상 메소드(메소드의 기능이 없고 메소드의 헤더부만 존재하는 불완전한 메소드)를 0개 이상 포함하는 클래스**로 스스로 자신의 생성자를 활용한 **인스턴스 생성이 불가능**하다. 따라서 추상 클래스는 **불완전한 클래스**라고 볼 수 있다.
추상 클래스는 상속을 활용해 하위 클래스 타입의 인스턴스를 이용해서 인스턴스를 생성해야 한다.
추상 메소드를 하나라도 포함하면 불완전하다고 볼 수 있는 클래스이므로 반드시 추상 클래스가 되어야 한다.
1-2. 추상 클래스를 사용하는 이유
💡 추상 클래스는 스스로 인스턴스는 만들지 못하지만 **다형성 적용을 위한 부모 타입 역할**을 해 낼 수 있다.
추상 메소드를 포함한 추상 클래스는 추상 메소드를 통해 자식 클래스에 오버라이딩에 대한 **강제성을 부여**할 수 있다.
(추상 클래스를 상속받는 자식 클래스는 반드시 추상 메소드를 오버라이딩 해야 한다.)
이는 필수 기능을 정의해 **일관된 인터페이스(동일 기능)를 제공**함에 있어 도움이 된다.
2. 인터페이스
2-1. 인터페이스(Interface)란?
💡 추상 메소드와 상수 필드만 가질 수 있는 클래스의 변형체이다.
상속과 달리 **implements**라는 키워드를 사용하며 자식 클래스 입장에서 ‘상속 받았다’고 말하지 않고 **‘구현한다’**라는 표현을 쓴다.
interface TestInter {
public static final PI1 = 3.1415;
PI2 = 3.14;
public abstract void method1();
void method2();
}
- 인터페이스를 구현하기 위해서는 implements 키워드를 사용해야 한다.
class Person implements Instinct, Serializable {
@Override
public void eating(String food) {
System.out.println("사람은 " + food + "를 요리하고 식기를 활용해 음식을 먹는다.");
}
}
2-2. 인터페이스를 사용하는 이유
💡 인터페이스는 공유를 목적으로 하는 상수(public static final 필드)를 기반으로 모든 기능을 공통화(public abstract 메소드)해서 강제성을 부여할 목적으로 만들어 졌다.(공통된 인터페이스)
또한 자바의 단일 상속이라는 단점을 어느 정도 극복하기 위해 사용되기도 하며 모든 클래스는 하나의 부모 클래스 외에도 여러 개의 인터페이스를 구현할 수 있다.
- 여러 인터페이스를 구현하는 클래스

public class Application implements InterOne, InterTwo {
@Override
public void interOneMethod() {}
@Override
public void interTwoMethod() {}
}
3. 추상 클래스와 인터페이스의 공통점과 차이점
3-1. 추상 클래스와 인터페이스의 차이점
| 구분 | 추상 클래스 | 인터페이스 |
|---|
| 상속 가능 범위 | 단일 상속 | 다중 상속 |
| 키워드 | extneds 사용 | implements 사용 |
| 추상 메소드 갯수 | abstract 메소드 0개 이상 | 모든 메소드는 abstract |
| abstract 키워드 명시 | 명시적 사용 | 묵시적으로 abstract |
3-2. 추상클래스와 인터페이스의 공통점
| 구분 | 추상 클래스 | 인터페이스 |
|---|
| 자체 인스턴스 생성 | 생성 불가 | 생성 불가 |
| 다형성 적용 시 상위 타입
활용 가능 유무 | 가능 | 가능 |