신입(혹은 저연차) 개발자의 단골 질문! 추상클래스와 인터페이스의 차이...! 많은 개발자들이 이 차이에 대해 단순히 표로만 비교한 정보를 가지고 답하겠지만 이들 중에는 이에 대해 제대로 이해하고 있는 사람은 드물다고 생각한다. 필자를 포함해서. 그래서 이번에 빠삭하게 정리해 보도록 하겠다. 핵심만 보려면 3번째 탭 '인터페이스와 추상클래스의 비교'만 보기를 추천드린다.
그리고 이 블로그 글과 검색 등을 이용해 정리했는데, 원글이 정리가 너무 잘 되어있어서 꼭 한번 보기를 바란다.
인터페이스 vs 추상클래스 차이점 완벽 이해하기
interface TV{
int MAX_VOLUME = 10; // public static final 생략 가능
int MIN_VOLUME = 10;
void turnOn(); // public abstract 생략 가능
void turnOff();
void changeVolume(int volume);
void changeChannel(int channel);
}
인터페이스 타입으로 변수를 구현하게 되면 모든 객체는 간단히 인터페이스만 구현한 객체이면 되기 때문에 좀 더 시스템이 유연해질 수 있다.
interface Keyboard{}
class Logitec_Keyboard implements Keyboard { }
class Samsung_Keyboard implements Keyboard { }
class Apple_Keyboard implements Keyboard { }
public class Main {
public static void main(String[] args) {
// 인터페이스 타입 배열로 여러가지 클래스들을 한번에 타입 묶음을 할 수 있다.
Keyboard[] k = {
new Logitec_Keyboard(),
new Samsung_Keyboard(),
new Apple_Keyboard()
};
}
}
또한, 적합한 인터페이스가 있다면 매개변수뿐만 아니라 반환값, 변수, 필드 전체를 전부 인터페이스 타입으로 선언하면 좋다.
- 객체는 인터페이스를 사용해 참조하라
- 적당한 인터페이스가 있다면 매개변수뿐만 아니라 반환값, 변수, 필드 전부 인터페이스 타입으로 선언하라
- 객체의 실제 클래스를 사용할 상황은 '오직' 생성자로 생성할 때 뿐이다
- 매개변수 타입으로는 클래스보다 인터페이스를 활용하라
예를들어 중복이 없는 집합 자료형을 사용하기 위해 LinkedHashSet 클래스를 초기화 하려할때, 이때 객체의 타입을 똑같이 LinkedHashSet 으로 하지말고 인터페이스인 Set 타입으로 설정하여 선언하는 것이다.
이런식으로 코드 구현을 해놓는다면, 나중에 변수에 담긴 구현 클래스를 다른 Set 자료형 클래스로 교체하고자 할때 그저 새 클래스의 생성자를 다시 호출해주기만 하면 되어 간편해진다.
// 나쁜 예) 클래스를 바로 타입으로 사용했다
LinkedHashSet<Object> s = new LinkedHashSet<>();
// 좋은 예) 인터페이스를 타입으로 사용했다
Set<Object> s = new LinkedHashSet<>();
// 좋은 예를 사용시 다른 Set자료형 교체가 쉽다
s = new TreeSet<>();
기본적으로 자바의 클래스 상속 구조는 부모-자식 관계로만 가능하고, 단일 상속의 원칙을 가진다. 하지만 인터페이스는 클래스 상속관계와는 달리, 하나의 기능에 대한 약속
이기 때문에 다중 상속에 제약받지 않으며, 일부만 묶고 싶은 클래스들을 implements키워드로 등록시키면, 각기 다른 부모클래스를 상속하고 있는 자식 클래스에 인터페이스를 구현(상속)시켜줌으로써 아무 관계도 없는 클래스들의 관계를 맺어줄 수 있다.
그림을 보면 쉽게 이해할 수 있다
예를 들어 각기 다른 부모 클래스를 상속하고 있는 Soccer 클래스와 BassGuitar 클래스를 하나의 타입으로 묶어서 사용할 필요가 있을때, 인터페이스를 implements 함으로써 마치 Soccer 와 BassGuitar 클래스를 묶은 형제 클래스 타입 IBehavior 를 만든것과 같다.
파라미터로 접근 가능한 타입을 제한할 수 있다
이 부분은 바로 코드 예시를 보는 것이 훨씬 이해하기 쉬울 수 있다.
다음과 같이 스타크래프트를 구성하기 위해 Marine, SCV, Tank 클래스를 만들고 이들을 공통으로 묶을 부모 클래스 GroundUnit 클래스로 상속 관계를 맺어 주었다.
그리고 repair() 메서드에서 중복을 줄이기 위한 다형성 기법으로 매개변수 타입을 GroundUnit 부모 클래스 타입으로 받도록 설정 하였다.
class GroundUnit { }
class Marine extends GroundUnit{ }
class SCV extends GroundUnit{ }
class Tank extends GroundUnit{ }
public class Main {
public static void main(String[] args) {
repair(new Marine());
}
static void repair(GroundUnit gu) {
// 마린은 기계가 아니기 때문에 수리는 불가능 하다. 하지만 상속 관계상 마린 클래스 타입이 들어와 실행될 수 있는 위험성이 존재한다.
}
}
하지만 위의 코드의 문제점은 기본적으로 repair 기능은 기계 유닛만 가능하여 SCV와 Tank 클래스 타입만 들어와야 되는데 생물 유닛인 Marine 클래스 타입도 상속 관계에 의해 들어 올수 있다는 것이다.
따라서 별도의 Machine 이라는 인터페이스를 선언하고 SCV, Tank 클래스에 implements 시킨다.
그렇게 3개의 자식중 2개의 자식만 머신 이라는 타입으로 형제 타입 관계를 맺어주면서 동시에 다른 타입의 접근 제한 역할도 해낸 것이다.
interface Machine { } // SCV, Tank 클래스를 통합한 타입으로 이용하는 인터페이스
class GroundUnit { }
class Marine extends GroundUnit{ }
class SCV extends GroundUnit implements Machine{ }
class Tank extends GroundUnit implements Machine{ }
public class Main {
public static void main(String[] args) {
repair(new Marine()); // ! ERROR
}
static void repair(Machine gu) {
// SVG와 탱크 타입만 받을 수 있게 인터페이스를 타입으로 하여 다형성을 적용
}
}
클래스의 관계를 상속(extends)가 아닌 구현(implements)으로 인터페이스로 확장시킨다면, 반환 타입이나 매개변수 타입으로 다른 객체와 소통하는 구간에 인터페이스 타입으로 사용함으로써, 객체간 의존성이 줄어들어 자신과 소통하는 객체의 변화에 강한 클래스를 만들 수 있게 된다.
클래스에 추상화를 접목시켜 보다 구조적이게 객체를 설계하고, 프로개름의 유지보수성을 올려주며, 만일 프로그램에 어떠한 기능을 업그레이드한다고 하면 수정/추가에 유연하게 해주는 기능의 클래스
메서드가 겹치는 클래스를 부모 추상클래스로 묶으면, 상속 특징을 이용하여 코드의 중복제거, 코드 재사용성 증대 효과를 누릴 수 있다
실제 프로젝트에서 어플리케이션 아키텍처가 설계해 놓은 추상 클래스를 상속받으면, 개발자는 프로젝트에서 필요하고 공통적으로 들어가야 하는 필드와 메서드를 오버라이딩해서 큰 설계를 생각할 필요 없이 구현만 하면 된다.
정리하자면 추상클래스를 상속받아서 미리 정의된 공통 기능들을 구현하고, 실제 클래스에서 필요한 기능을 클래스별로 확장시키면서 소스 수정시 다른 소스의 영향도를 적게 가져가면서 변화에는 유연하게 만들 수 있다.
public abstract
로 정의(default 메서드 제외)public static final
상수static
, default
, private
제어자를 붙여 클래스같이 구체적인 메서드를 가질 수 있음xxxable
이런 형식으로 인터페이스 네이밍 규칙을 따름이를 상속할 각 객체들의 공통점을 찾아 추상화시켜 놓은 것으로, 상속관계를 타고 올라갔을 때 부모클래스가 상속하며 부모클래스가 가진 기능을 구현해야 할 경우 사용한다
클래스와 별도로 구현 객체가 같은 동작을 한다는 것을 보장하기 위해 사용
출처 :
인터페이스 vs 추상클래스 차이점 완벽 이해하기
인터페이스(Interface) 문법 & 활용 - 완벽 가이드