인터페이스와 추상 클래스는 각각 상속(extends)받거나, 구현(Implements)하는 클래스가 그 안에 보유하고 있는 Abstract Method를 구현하도록 강제하는 공통점을 가지고 있다.
깊이 공부하다보면 둘 다 추상화를 달성하는 데 사용한다는 점을 알 수 있다. 또한 인터페이스와 추상 클래스 각각은 그 자체로 인스턴스화 될 수 없다. 비슷해보이는 둘 사이의 차이점을 알아보도록 하자.
추상 클래스는 상속 관계에 의미가 있다. 추상 클래스를 상속받아서 자식 클래스들 간에 공통 기능을 각각 구현하고, 확장이 가능하다.
추상 클래스를 상속하면서 자식 클래스들간의 구분이 더 명확해진다.
Java 언어에서는 다중 상속을 지원하지 않기 때문에 추상 클래스만으로 구현해야하는 추상 메서드를 강제하는데에는 한계가 존재한다. → 다중 상속은 모호성을 제거하기 위해서 지원하지 않는다.
abstract class Animal{
abstract void cry(); // 추상 클래스, 상속받는 자식클래스에서 반드시 구현해야 한다.
void normal(); // 일반 클래스, 구현하거나 구현하지 않거나 선택할 수 있다.
}
abstract class Cat extends Animal{
@Override
public void cry(){
System.out.println("냐옹냐옹!");
}
}
인터페이스는 다형성에 의미가 있다. 추상 클래스와 달리, 상속 관계에 얽매이지 않고, 공통 기능이 필요할 때, 추상 메서드를 정의하고 구현하는 클래스에서 각 기능들을 Override하여 여러가지 형태로 구현한다. 기본적으로 메서드를 선언하면 추상 메서드로 선언되며 Java 8 이후부터는 Default 메서드 혹은 static 메서드도 지원한다. Default 메서드의 경우, 오버라이딩도 가능하고 그대로 사용하는 것도 가능하다.
간단히 말하면 추상 클래스는 부분 추상화를 달성하고, 인터페이스는 완전한 추상화를 달성한다. 따라서 관련성이 높은 클래스 ( 동물 - 인간 )의 경우에는 추상 클래스를, 관련성이 없지만 기능을 위해 ( 달리기, 숨쉬기 ) 인터페이스를 사용한다.
표준 라이브러리의 예시를 들면 Comparable 과 같은 인터페이스는 단순히 비교를 위한 기능을 제공할 뿐, 클래스간의 연관관계는 없다.