개요
객체 지향 프로그래밍에서 추상 클래스(Abstract Class)와 인터페이스(Interface)는 중요한 개념이다. 이 두 가지는 코드의 재사용성과 유지 보수성을 높이는 데 도움을 주지만, 사용 방법과 목적에서 차이가 있다. 이번 포스팅에서는 추상 클래스와 인터페이스의 개념과 차이점을 명확히 하고, 언제 어떤 것을 사용해야 하는지에 대해 알아보겠다.
추상 클래스
추상 클래스는 클래스 간의 공통적인 기능을 정의하기 위한 미완성 설계도이다.
abstract 키워드를 사용하여 선언하며, 완성되지 않은 추상 메서드와 일반 메서드를 모두 포함할 수 있다.
public abstract class 추상클래스명 {
}
예를 들어, 다음과 같이 LibraryItem이라는 추상 클래스를 선언할 수 있다.
추상메서드가 없어도 추상 클래스로 선언할 수 있고, 자식 클래스에 상속되어 자식 클래스에 의해서만 완성될 수 있다.
public abstract class LibraryItem {
String title; // 책 제목
boolean isCheckedOut; // 대출 여부
// 생성자: 책 제목과 대출 상태를 초기화
public LibraryItem(String title) {
this.title = title;
this.isCheckedOut = false;
}
// 책을 대출하는 추상 메서드
abstract void checkOut();
// 책을 반납하는 추상 메서드
abstract void returnItem();
// 책의 정보를 출력하는 일반 메서드
void displayInfo() {
System.out.println("제목: " + title + ", 대출 여부: " + (isCheckedOut ? "대출 중" : "대출 가능"));
}
}
LibraryItem은 추상 클래스로, checkOut()과 returnItem()이라는 추상 메서드를 가지고 있다. 이 추상 메서드들은 상속받는 클래스에서 구현해야 한다.
// DVD 클래스: LibraryItem 추상 클래스를 상속받음
public class DVD extends LibraryItem {
int duration; // DVD의 총 재생 시간 (분 단위)
public DVD(String title, int duration) {
super(title); // 상위 클래스의 생성자 호출
this.duration = duration;
}
@Override
void checkOut() {
if (!isCheckedOut) {
isCheckedOut = true;
System.out.println(title + " DVD가 대출되었습니다.");
} else {
System.out.println(title + " DVD는 이미 대출 중입니다.");
}
}
@Override
void returnItem() {
if (isCheckedOut) {
isCheckedOut = false;
System.out.println(title + " DVD가 반납되었습니다.");
} else {
System.out.println(title + " DVD는 대출 상태가 아닙니다.");
}
}
// DVD 클래스에 추가로 정의된 멤버 메서드
void playDVD() {
System.out.println(title + " DVD를 재생합니다.");
}
}
DVD 클래스는 LibraryItem을 상속받아, 추상 메서드들을 구체적으로 구현하였다.
인터페이스
인터페이스는 구현된 것은 아무것도 없는 기본 설계도와 같은 역할을 한다. 모든 메서드는 기본적으로 추상적이며, 자바 8 이후부터는 default 메서드와 static 메서드를 통해 일부 구현을 제공할 수도 있다. 인터페이스의 주요 목적은 다양한 클래스들이 동일한 메서드 집합을 구현하도록 보장하는 것이다.
예를 들어, 다음과 같이 Electric이라는 추상 클래스를 선언할 수 있다.
interface Electric {
void chargeBattery(); // 충전 메서드 (추상 메서드)
}
Electric 인터페이스는 전기 충전 기능을 구현해야 하는 클래스가 반드시 chargeBattery() 메서드를 구현하도록 강제한다.
추상 클래스와 인터페이스의 공통점
인스턴스화 불가능
둘 다 객체를 생성할 수 없다.
LibraryItem libraryItem = new LibraryItem(); // ERROR: 'LibraryItem' is abstract; cannot be instantiated
Electric electric = new Electric(); // ERROR: 'LibraryItem' is abstract; cannot be instantiated
추상 메서드 포함
둘 다 추상 메서드를 포함할 수 있다.
강제 구현
상속받거나 인터페이스를 구현하는 클래스는 반드시 추상 메서드를 재정의하여 구현해야 한다.
차이점
구분 | 추상 클래스 | 인터페이스 |
개념적 목적 | 상속받아서 기능을 확장시키는데 목적이 있다. | 구현 객체의 동일한 실행 기능을 보장하기 위한 목적이 있다. |
클래스 | 클래스다 (abstract class). | 클래스가 아니다 (interface). |
일반 메서드 | 일반 메서드 정의가 가능하다. | 일반 메서드 정의 불가능(Java 8 이후 static, default 메서드 정의 가능). |
멤버 변수 | 클래스와 동일하게 변수 선언 및 사용 가능하다. | 상수만 사용 가능하다. (public static final) |
상속 키워드 | extends | implements |
다중 상속 | 불가능하다. | 가능하다. |
다중 상속
Java에서는 클래스의 다중 상속을 지원하지 않지만, 인터페이스에서는 다중 상속을 구현할 수 있다. 인터페이스의 모든 메서드는 추상 메서드이기 때문에 동일한 이름의 메서드가 있어도 상속받는 클래스에서 재정의(오버라이딩) 해야 하므로, 다중 상속의 모호성 문제가 발생하지 않는다.
interface Chargeable {
void charge(); // 충전하는 메서드
}
interface SmartDevice {
void connectToWifi(); // Wi-Fi 연결 메서드
void controlViaApp(); // 앱으로 제어하는 메서드
}
class SmartFridge implements Chargeable, SmartDevice {
@Override
public void charge() {
System.out.println("냉장고의 배터리를 충전합니다.");
}
@Override
public void connectToWifi() {
System.out.println("냉장고를 Wi-Fi에 연결합니다.");
}
@Override
public void controlViaApp() {
System.out.println("앱을 통해 냉장고를 제어합니다.");
}
// SmartFridge 클래스에 추가된 메서드
void coolFood() {
System.out.println("음식을 냉장합니다.");
}
}
SmartFridge 클래스는 Chargeable과 SmartDevice라는 두 개의 인터페이스를 다중 상속받아 각각의 기능을 모두 구현하고 있다. 이를 통해 다양한 기능을 한 클래스에서 구현할 수 있으며, 코드의 유연성과 재사용성을 높일 수 있다.
결론
추상 클래스와 인터페이스는 각각의 목적에 맞게 사용되어야 한다. 추상 클래스는 공통 기능을 공유하고 확장할 때, 인터페이스는 서로 다른 클래스들이 동일한 기능을 구현하도록 강제할 때 유용합니다. 이 두 개념의 차이를 명확히 이해하면, 더 나은 객체 지향 설계를 할 수 있다.
'JAVA' 카테고리의 다른 글
UncheckedException과 CheckedException (1) | 2024.09.13 |
---|---|
ArrayList는 어떻게 크기가 조절될까? (0) | 2024.09.11 |
Garbage Collection(GC) 더 자세히 살펴보기 (0) | 2024.09.09 |
Java final과 불변성 (0) | 2024.09.08 |
가비지 컬렉션이란? (1) | 2024.09.06 |
제네릭이란? (2) | 2024.09.04 |
나만의 메서드가 한 가지 기능만 하는지 확인하는 기준 (0) | 2023.10.07 |
좋은 코드를 위한 네이밍 기법들 (0) | 2023.09.27 |