자바 추상 클래스와 인터페이스의 차이점 이해하기
'is a kind of(~의 한 종류) 추상 클래스'와 'be able to(~할 수 있는) 인터페이스'
- 추상 클래스
public abstract class 클래스이름 {
...
public abstract void 메서드이름();
}
class 앞에 'abstract' 키워드를 사용하여 정의하며, 하나 이상의 추상 메서드를 가지는 클래스를 말합니다. 추상 메서드를 선언하여 상속을 통해서 하위 클래스에서 (반드시) 구현하도록 강제하는 클래스입니다.
(추상 메서드를 포함하지 않는 클래스에서도 abstract를 붙여서 추상 클래스로 지정할 수 있으며, 반대로 추상 메서드를 포함하는 클래스는 반드시 추상 클래스여야 합니다.)
abstract로 선언된 추상 클래스는 상속을 위한 클래스이기 때문에 new 키워드를 통해 직접 객체를 생성할 수 없다는 특징이 있습니다. 또한 java에서는 다중 상속을 지원하지 않기 때문에 여러 개의 추상 클래스를 상속할 수는 없습니다.
추상 메서드란,
선언부만 작성하고 구현부는 작성하지 않은 채로 남겨두는 것이 추상 메서드이며, 상속받는 클래스에 따라서 구현되는 내용이 달라질 수 있습니다.
***
인터페이스와 다르게 static이나 final이 아닌 필드를 가질 수 있고, public protected, private 접근 제어자를 모두 사용할 수 있습니다.
public abstract class AbstractClass {
// Field
private String name;
// Constructor
public AbstractClass(String name) {
this.name = name;
}
// Method
public void method() { };
}
public class RealClass extends AbstractClass {
private String address;
public RealClass(String name, String address) {
super(name);
this.address = address;
}
}
***
추상 클래스는 상속을 통해서만 사용 가능하며, 하위 클래스의 생성자에서 super()를 사용해서 추상 클래스의 생성자를 부르고 초기화시킵니다.
- 인터페이스
interface 인터페이스이름 {
...
public abstract void 메서드이름();
public default void 메서드이름() {};
}
'interface' 키워드를 사용하여 선언하는 인터페이스는 상수(static final)와 추상 메서드(abstract method)의 집합입니다.
인터페이스는 추상 클래스보다 추상화 정도가 높으며 추상 클래스와는 다르게 구현부가 있는 일반 메서드, 일반 멤버 변수를 가질 수 없다는 특징이 있습니다.
인터페이스의 모든 메서드는 'public abstract'로 선언해야 하며, 이를 생략할 수 있습니다. 또한 모든 멤버 변수는 'public static final'으로 선언해야 하며, 마찬가지로 이를 생략할 수 있습니다.
(생략할 수 있는 이유는 컴파일 시 자동으로 생성해주기 때문입니다.)
Serializable : 직렬화할 수 있는
Closeable : 스트림을 닫고 시스템 리소스를 해제할 수 있는
Appendable : char 시퀀스 및 값을 추가할 수 있는
java에 구현된 몇 가지 인터페이스 예시입니다.
맨 앞에서 언급한 것처럼 인터페이스는 'be able to (~를 할 수 있는)' 특징을 가지고 있습니다. 때문에 인터페이스는 xxxable 이라는 네이밍 규칙을 가지며, 인터페이스를 구현하는 구현체는 xxxImpl 같이 네이밍 하는 경향이 있습니다.
(구현체는 인터페이스를 구현한 클래스라는 뜻이며, 구현 클래스 또는 실체 클래스라고도 부릅니다.)
인터페이스는 추상 클래스와는 다르게 다중 상속이 가능하다는 특징이 있습니다.
*** JDK1.8 도입된 default method
JDK1.8부터 static 메서드와 default 메서드를 사용할 수 있게 되었습니다. defualt 메서드의 목적은 기존 인터페이스의 기능을 확장하며, 구현체에 공통적으로 들어갈 기능(코드)을 디폴트 메서드 내부에서 작성함으로써 구현체에서 반복되는 코드의 작성을 줄여줍니다.
*** public static final를 사용하는 목적
인터페이스는 인스턴스가 존재할 수 없기 때문에 상속받은 구현 객체에서 같은 상태를 보장하기 위해서 public static final을 사용합니다.
- 추상 클래스와 인터페이스의 공통점과 차이점
이 둘의 공통점은 메서드의 선언만 있고, 구현 내용이 없다는 것입니다. (추상 메서드)
new 키워드를 통해 객체를 생성할 수 없으며, 상속받은 클래스가 반드시 선언된 추상 메서드를 구현하도록 한다는 것입니다.
차이점으로는 추상 클래스는 extends 키워드를 사용하여 상속하며, 다중 상속은 불가능합니다. 반면 인터페이스는 implements 키워드를 사용하여 상속하며, 다중 상속이 가능합니다.
또 추상 클래스는 일반 변수, 생성자, 일반 메서드, 추상 메서드를 모두 가질 수 있는 반면 인터페이스는 상수와 추상 메서드만 가질 수 있고, 생성자와 일반 변수는 가질 수 없습니다.
개념적 차이점이 아닌 실제 적용하는 것에서 차이점을 생각해보면,
추상 클래스는 extends(상속, 확장의 느낌) 키워드 그대로 자신의 기능들을 하위로 확장시키는 것으로 볼 수 있습니다.
인터페이스는 implements(상속, 구현의 느낌) 키워드처럼 인터페이스에 정의된 메서드를 각 클래스의 목적에 맞게 동일한 기능으로 구현하는 것으로 볼 수 있습니다.
또 다른 관점에서는 추상 클래스는 이를 상속할 각 객체들의 공통점을 찾아 추상화시켜놓은 것으로 상속 관계를 타고 올라갔을 때, 같은 부모 클래스를 상속하며, 부모 클래스가 가진 기능들을 구현해야 하는 경우에 사용합니다.
반면 인터페이스는 상속 관계를 타고 올라갔을 때, 다른 부모 클래스를 상속하더라도 같은 기능이 필요한 경우에 사용됩니다.
***
정리하자면 자바의 특성상 한 개의 클래스만 상속이 가능하기 때문에 해당 클래스의 구분을 추상 클래스 상속을 통해서 해결하고, 할 수 있는 공통된 기능들을 인터페이스의 다중 상속을 통해 구현합니다.
***
상위 클래스는 다중 상속이 불가능하기 때문에 하나의 클래스에서 하위 클래스에 물려줄 특성이 풍부할수록 좋고, 인터페이스는 다중 상속이 가능하기 때문에 각각의 인터페이스는 목적에 맞는 최소한의 메서드(구현을 강제할)를 선언하는 것이 좋습니다.
(추상 클래스와 인터페이스 관계 참고 이미지)
< 함께 보면 이해하기 좋은 글 >
< 참고 자료 >