인터페이스와 내부 클래스는 구현과 선언을 분리하는 구조화된 방식을 제공합니다.
JAVA 언어에서 추상 개념을 정의하는 두 가지 메커니즘인 추상 클래스와 인터페이스는 JAVA가 강력한 객체 지향 기능을 갖도록 만드는 핵심 요소입니다. 이 둘은 추상 개념 지원 면에서 유사성이 크고 상호 교체 가능하나, 설계적 차이점이 존재합니다.1. 추상 클래스
객체 지향 세계에서는 모든 것이 객체로 구성되며, 객체는 클래스로 표현됩니다. 그러나 모든 클래스가 객체를 설명하는 것은 아닙니다. 특정 클래스가 구체적인 객체를 설명할 수 없고 다른 클래스에 의존해야 할 경우, 이를 추상 클래스로 간주합니다. 예를 들어, Animal 클래스는 실제 동물 객체를 생성하지 않으며, 구체적인 동물(강아지, 고양이 등)을 통해 특성화되어야 합니다.
추상 클래스는 데이터 추상화 개념을 반영하며 다형성의 기초가 됩니다. 추상 메서드는 파생 클래스에서 구현되며, 상속을 통한 설계 목적을 가집니다. 추상 클래스는 반드시 상속을 위해 존재하며, 상속 계층 구조에서 리프 노드는 구체적인 구현 클래스여야 합니다.
추상 클래스 사용 시 주의사항:
- 추상 클래스는 직접 인스턴스화 불가능하며, 자식 클래스가 인스턴스화 작업을 담당해야 합니다.
- 추상 메서드는 자식 클래스에서 재정의되어야 합니다.
- 단 하나의 추상 메서드라도 포함되면 전체 클래스가 추상 클래스로 정의되어야 합니다.
- 구체적인 메서드도 포함될 수 있으며, 추상 메서드가 없는 경우도 있습니다.
- 자식 클래스의 추상 메서드는 부모 클래스의 추상 메서드와 이름이 중복될 수 없습니다.
- abstract 키워드는 final 키워드와 함께 사용할 수 없습니다.
- abstract 메서드는 private, static, final, native 키워드와 함께 사용할 수 없습니다.
예시:
public abstract class Mammal {
public abstract void makeSound();
}
public class Tiger extends Mammal {
@Override
public void makeSound() {
System.out.println("호랑이 소리: 으르렁...");
}
}
public class Dog extends Mammal {
@Override
public void makeSound() {
System.out.println("개 소리: 외우...");
}
}
public class Test {
public static void main(String[] args) {
Mammal m1 = new Tiger();
Mammal m2 = new Dog();
m1.makeSound();
m2.makeSound();
}
}
출력 결과:
호랑이 소리: 으르렁... 개 소리: 외우...
2. 인터페이스
인터페이스는 추상 클래스보다 더 추상적인 "클래스"로 간주됩니다. 인터페이스 자체는 클래스가 아니며, 인스턴스화 불가능합니다. 예를 들어, new Runnable()는 오류를 발생시키며, 실제로는 구현 클래스를 인스턴스화해야 합니다.
인터페이스는 클래스 간의 협약을 정의하며, 구현 방법은 해당 클래스에서 결정됩니다. 인터페이스는 클래스가 특정 규약을 준수함을 나타내며, "인터페이스는 외형이며, 구현 방식은 개발자가 정의해야 합니다"라는 의미입니다.
인터페이스는 추상 클래스의 한계를 보완하며, 단일 상속 제약을 해결합니다. 클래스는 여러 인터페이스를 동시에 구현할 수 있어 다중 상속 효과를 제공합니다. 하지만 추상 클래스와 인터페이스를 병행 사용하는 것이 일반적입니다.
인터페이스 사용 시 주의사항:
- 인터페이스의 모든 메서드는 자동으로 public 접근 권한을 갖습니다.
- 인터페이스 내부 변수는 자동으로 public static final로 처리됩니다.
- 인터페이스는 구현 메서드를 포함할 수 없습니다.
- 구현 클래스는 인터페이스의 모든 메서드를 구현해야 하며, 추상 클래스는 선택적으로 구현할 수 있습니다.
- 인터페이스 인스턴스화는 불가능하지만, 참조 변수로 사용 가능하며 instanceof 연산자를 사용해 확인 가능합니다.
- 다중 인터페이스 구현 시 메서드 이름 충돌을 피해야 합니다.
3. 추상 클래스 vs 인터페이스 차이점
3.1 문법적 차이:
추상 클래스 예시:
public abstract class Demo {
abstract void method1();
void method2() {
// 구현
}
}
인터페이스 예시:
interface Demo {
void method1();
void method2();
}
추상 클래스는 다양한 접근 범위의 멤버 변수와 비추상 메서드를 포함할 수 있지만, 인터페이스는 static final 멤버 변수만 허용하며 모든 메서드는 추상 메서드로 처리됩니다.
3.2 설계적 차이:- 추상 클래스는 클래스 전체를 추상화하며, 속성과 행동을 모두 포함합니다. 반면 인터페이스는 특정 행동만 추상화합니다. - 추상 클래스는 유사한 특성을 공유하는 클래스 간 관계를 표현하고, 인터페이스는 서로 관련 없는 클래스 간 협약을 정의합니다. - 추상 클래스는 하위 클래스부터 추상화를 시작하는 반면, 인터페이스는 상위 개념부터 정의되는 설계 방식입니다.
실제 예시:
문의 기능을 구현하는 두 개의 인터페이스를 사용한 설계:
abstract class Door {
abstract void open();
abstract void close();
}
interface Alarm {
void alarm();
}
class AlarmDoor extends Door implements Alarm {
void open() {}
void close() {}
void alarm() {}
}
이 설계는 문제 영역의 이해를 반영하며, 추상 클래스는 "is-a" 관계, 인터페이스는 "like-a" 관계를 표현합니다.
4. 요약
- 추상 클래스는 상속 관계를 나타내며, 하나의 부모 클래스와 여러 인터페이스를 가질 수 있습니다. - 추상 클래스는 멤버 변수와 비추상 메서드를 포함할 수 있지만, 인터페이스는 static final 멤버 변수만 허용하며 모든 메서드는 추상 메서드입니다. - 추상 클래스는 "is-a" 관계를, 인터페이스는 "like-a" 관계를 나타냅니다.