추상 클래스와 인터페이스는 모두 코드의 독립성과 일관성을 유지하는 것에 도움을 준다. 또한 둘 다 내부적으로 abstract 키워드
가 붙은 추상 메서드
를 갖고 있고, 추상 클래스를 상속 받은 자식 클래스와 인터페이스를 implements한 클래스는 모두 이 추상 메서드를 필수적으로 override
하여 공통된 기능을 자신에게 맞게 재정의
한다.
추상 클래스와 인터페이스가 코드의 일관성을 유지하게 해준다는 말은, 이것들을 상속 혹은 implements할 클래스들이 어떤 기능을 필수적으로 구현해야하는지에 대해 강요하며, 규격을 만들어둔다는 뜻이다. 이렇게 해두면, 서로 다른 자식 클래스에서 비슷한 기능을 조금씩 다른 이름을 사용하여 구현하는 식으로 자바의 다형성을 깨는 행위를 막아줄 수 있다.
또한, 추상 클래스와 인터페이스는 일반적 상속과 마찬가지로 연관 관계가 없던 클래스들 간에 관계를 만들어주며, 하나의 그릇(자료형)에 담길 수 있도록 묶어주는 역할을 한다. 이렇게 여러 클래스형들을 하나의 자료형에 담아둘 수 없다면 같은 추상 클래스나 인터페이스를 구현한 클래스들끼리 자료형을 조금 바꾸고 싶어도 그것을 사용하는 모든 코드를 수정해야하는데, 추상 클래스와 인터페이스가 이런 상황을 막아준다.
한편 인터페이스는 클래스의 선언과 구현을 완전히 분리시킨 모양인데, 이를 통해 실제 구현에 독립적인 프로그램을 작성할 수 있다. 또한 클래스와 클래스 간의 직접적인 관계를 인터페이스를 이용한 간접적 관계로 변경하면, 한 클래스의 변경이 다른 클래스에 영향을 미치지 않기 때문에 독립적 프로그래밍이 가능해진다.
< 추상 클래스 구현 시 주의할 점 >
<인터페이스 구현 시 주의할 점>
인터페이스도 일반적 상속 관계와 마찬가지로(추상 클래스는 일반적 상속의 확장 범위이므로 당연히 가능하다), 인터페이스를 implements한 클래스들의 객체는 인터페이스로 자동 형변환이 가능하다. (이전 포스팅에서도 언급했듯 부모-자식 간의 자동 형변환이 가능해야만 같은 인터페이스를 implements한 서로 다른 클래스를 한 곳에 모을 수 있기 때문에, 자동 형변환은 그 자체로 자바의 다형성 구현과 깊은 관련이 있다.)
직접 인터페이스를 구현하는 경우, 인터페이스는 코드의 독립성, 일관성 유지의 역할을 한다. 즉 설계의 틀을 만들어두고 표준화시킬 수 있게 한다.
또한 자바 프로그래밍을 하다보면 API로 정의된 인터페이스들을 사용할 수 있는데, 이 경우 이 인터페이스들에 정의된 추상 메서드를 override하는 방식으로 기능을 쉽게 구현할 수 있다(ex. Thread).
또한, 자바에서는 원래 다중 상속이 가지는 문제점(부모 클래스들에 같은 이름을 갖는 메서드가 있다면 어떤 것을 override하는 것인지 명시하기 어려움,...) 때문에 이를 허용하지 않는데, 인터페이스를 이용하면 다중 상속과 유사한 효과를 낼 수 있다.
그렇다면 인터페이스는 다중 상속의 side effect를 똑같이 가질까?
그렇지 않다. 인터페이스의 메소드는 모두 추상 메소드이므로 메소드명이 겹치더라도 인터페이스를 implements한 클래스에서 해당 메소드를 실제로 구현하므로 문제기 발생하지 않는다.
추상 클래스: 클래스 내 추상 메서드가 하나 이상 포함된 경우. 생성자를 가질 수 있으며, 일반 멤버 변수나 메서드를 갖는 것도 가능하다. 즉, 추상 메서드를 포함한다는 것 외에 일반 클래스와의 차이점은 없다.
인터페이스: 모든 메서드가 추상 메서드인 경우 (단, 예외적으로 jdk 1.8부터는 default 키워드를 이용해서 일반 메서드 구현도 가능할 수 있고, static 메서드도 가질 수 있다). 변수로는 상수만을 가질 수 있다.
cf.
static 메서드 -> 인스턴스와 관계가 없는 독립적 메서드이므로 있어도 무관
default 키워드 -> 인터페이스는 설계도를 만드는 작업인데, 이 설계도가 수정되지 않는게 가장 좋은 설계이겠지만,
어쩔 수 없이 수정해야할 경우 이를 implements한 모든 클래스를 수정하는 것을 막기 위해 추가되었다.
추상 클래스: 추상 클래스의 상속을 통해 기능을 이용하고 확장시키는 것(일반적 상속과 유사)
인터페이스: 구현돼있는 기능은 없고, 메서드의 껍데기만 존재하여 특정 기능 구현을 강제