추상클래스와 인터페이스는 왜 비슷하지만 쓰임이 다를까?

박화랑·2025년 3월 10일
0

Spring_6기

목록 보기
10/15

추상화(Abstraction)란?

개발하다 보면 궁금한 점이
"이 코드에서 진짜 중요한 건 뭘까?"
"굳이 세부 구현까지 다 신경 써야 할까?" 란 의문이 생겼다.

이럴 때 필요한 게 바로 추상화(Abstraction)를 사용할 수 있다.

추상화는 중요한 부분만 남기고, 불필요한 세부 사항은 감추는 것이라고 한다.
예를 들어, "동물"이라는 개념을 생각해보자.
모든 동물은 "걷다", "먹다", "자다" 같은 공통적인 동작을 하지만 강아지는 짖고, 고양이는 야옹하고, 새는 나는 등의 추가 동작을 한다.

이걸 프로그래밍적으로 표현하려면 공통적인 기능은 하나로 묶고, 각 동물마다 다른 행동은 따로 구현하면 편해질 것이다.
이런 개념이 바로 추상 클래스인터페이스로 표현될 수 있다.


추상 클래스 vs 인터페이스, 뭐가 다를까?

이제 추상 클래스와 인터페이스의 차이점을 간단히 비교하자면...

구분추상 클래스인터페이스
목적기본 기능을 제공하면서 확장 가능특정 기능을 정의하고 공유
다중 상속❌ 안 됨 (extends는 한 개만 가능)✅ 가능 (implements 여러 개)
추상화 수준일부 구현 O, 일부만 강제모든 메서드를 강제 (Java 8부터 default 가능)
변수private, protected, public 사용 가능public static final(상수)만 가능
언제 사용?기본 기능을 상속하며 확장할 때기능을 강제하고 싶을 때

추상 클래스, 언제 쓸까?

추상 클래스는 공통 기능을 미리 제공하면서, 일부만 강제하고 싶을 때 유용하다.
예를 들어, 스마트폰을 생각해보면

abstract class Smartphone {
    void powerOn() { // ✅ 공통 기능
        System.out.println("전원이 켜졌습니다.");
    }

    abstract void useAssistant(); // ✅ 강제 구현
}

class iPhone extends Smartphone {
    @Override
    void useAssistant() {
        System.out.println("Siri를 실행합니다.");
    }
}

class Galaxy extends Smartphone {
    @Override
    void useAssistant() {
        System.out.println("Bixby를 실행합니다.");
    }
}

public class Main {
    public static void main(String[] args) {
        Smartphone iphone = new iPhone();
        iphone.powerOn();
        iphone.useAssistant();

        Smartphone galaxy = new Galaxy();
        galaxy.powerOn();
        galaxy.useAssistant();
    }
}

➡️ powerOn()은 모든 스마트폰이 공통으로 가지는 기능이니까 미리 구현해두고,
➡️ useAssistant()는 각 스마트폰마다 다르니까 강제 구현하도록 추상 메서드로 만든 것이다.


인터페이스, 언제 쓸까?

인터페이스는 여러 개의 기능을 동시에 구현해야 할 때 유용하다.
스마트폰이 충전도 되고, 블루투스도 연결할 수 있기 때문에, 이 두 기능을 따로 떼어서 생각해볼 수 있다.

interface Chargeable {
    void charge();
}

interface BluetoothConnectable {
    void connectBluetooth();
}

class Smartphone implements Chargeable, BluetoothConnectable {
    @Override
    public void charge() {
        System.out.println("스마트폰 충전 중...");
    }

    @Override
    public void connectBluetooth() {
        System.out.println("블루투스 연결됨");
    }
}

public class Main {
    public static void main(String[] args) {
        Smartphone phone = new Smartphone();
        phone.charge();
        phone.connectBluetooth();
    }
}

➡️ Chargeable, BluetoothConnectable 두 개의 기능을 따로 정의하고, 스마트폰이 둘 다 구현하도록 한 것.
➡️ 만약 추상 클래스를 썼다면 다중 상속이 안 되니까 이런 구조를 만들 수 없었을 것이다.


정리하면...

추상 클래스랑 인터페이스를 최종적으로 비교하자면...

"다중 상속이 필요해?"
✔ 필요하면 인터페이스
✔ 필요 없으면 추상 클래스

"공통 기능을 포함할 거야?"
✔ 포함하려면 추상 클래스
✔ 기능 강제만 필요하면 인터페이스

"확장성이 중요해?"
✔ 확장하려면 추상 클래스
✔ 기능만 제공하려면 인터페이스

즉,
👉 "공통 기능 + 확장성"추상 클래스
👉 "강제성 + 다중 구현"인터페이스

이 두가지만 확실하게 기억해두자!!!!

profile
개발자 희망생

0개의 댓글

관련 채용 정보