김코딩

둘 다 객체 못 만든다면서요? 그런데 왜 둘이나 있는 거죠?(인터페이스 VS 추상클래스) 본문

TIL

둘 다 객체 못 만든다면서요? 그런데 왜 둘이나 있는 거죠?(인터페이스 VS 추상클래스)

김코딩딩 2025. 4. 25. 14:44

이번에는 추상클래스와 인터페이스의 차이점에 대해 이야기해보겠습니다.


추상클래스의 주요 특징

  1. 객체를 직접 생성할 수 없습니다.
    new 키워드로 인스턴스를 만들면 컴파일 에러가 발생합니다.
  2. 추상 메서드를 포함할 수 있으며,
    추상클래스를 상속받은 자식 클래스는 이 추상 메서드를 반드시 오버라이딩해야 합니다.
  3. 모든 메서드가 추상 메서드로만 구성된 클래스
    순수 추상 클래스(Pure Abstract Class) 라고 하며,
    이 구조는 인터페이스와 매우 유사한 형태입니다.

인터페이스란? 

인터페이스(Interface)는기능의 설계서 또는 규칙의 집합이라고 할 수 있습니다.
클래스에게"이 기능을 꼭 구현해!"라고 강제하는계약서 같은 존재입니다.

 

인터페이스 선언

public interface 인터페이스명 {
    //public 상수 필드
    //public 추상 메소드
    //public 디폴트 메소드
    //public 정적 메소드
    //private 메소드
    //private 정적 메소드
}

 

인터페이스는 순수 추상 메서드와 같지만 약간의 편의 기능이 추가되었습니다.

  • 인터페이스는 원래 모든 메서드가 public abstract 였습니다.
    메서드에 public abstract를 생략해도 되며, 생략하는 것이 일반적입니다.
  • 자바 8 이후부터는 default 메서드, static 메서드,
    자바 9부터는 private 메서드도 선언 가능합니다.
  • 다중 구현(다중 상속)을 지원합니다.
    → 한 클래스가 여러 개의 인터페이스를 구현할 수 있습니다.

추상클래스 VS 인터페이스

구분 추상클래스 (abstract class) 인터페이스 (interface)
객체 생성 불가능 불가능
상속/구현 키워드 extends (단일 상속만 가능) implements (다중 구현 가능)
다중 상속 안 됨 가능
필드 선언 일반 필드 선언 가능 모든 필드는 public static final (상수)
메서드 선언 일반 메서드 + 추상 메서드 모두 가능 기본은 추상 메서드, Java 8 이후 default, static 메서드 가능
접근 제어자 자유롭게 설정 가능 (private, protected, etc.) 모든 메서드는 기본적으로 public (생략 가능)
생성자 가질 수 있음 (하지만 객체는 못 만듦) 생성자 정의 불가능
용도 공통된 기능 제공 + 상속 구조 설계 기능 명세(규칙) 제공, 다형성의 극대화
자바 클래스 상속 클래스는 단 하나의 추상클래스만 상속 가능 클래스는 여러 인터페이스를 동시에 구현 가능

 


그런데 궁금하지 않으신가요?

“순수 추상 클래스와 인터페이스가 그렇게 비슷하다면,
굳이 인터페이스라는 개념이 또 나와야 할까요?”

 

순수 추상 클래스는 인터페이스와 거의 동일한 기능을 제공합니다.
실제로 모든 메서드가 추상 메서드로만 구성된 추상 클래스는 인터페이스처럼 동작합니다.

하지만 이 구조에는 잠재적인 문제가 존재합니다.
미래에 누군가 이 클래스에 일반 메서드를 추가하게 된다면,
더 이상 "순수 추상 클래스"가 아니게 됩니다.

또한, 인터페이스는 다중 상속이 가능하기 때문에
클래스 구조를 유연하게 설계할 수 있다는 점에서도 차별점이 있습니다.

 


그러면 언제 무엇을 써야할까요?

사실 추상 클래스와 인터페이스 모두 "공통 기능을 정의하고 강제하는 도구"입니다.
하지만 사용하는 목적과 상황에 따라 선택 기준이 달라집니다.


추상 클래스가 더 적합한 경우

  • 공통된 상태(필드)와 동작(일반 메서드)을 함께 제공하고 싶을 때
  • 상속받는 클래스들 사이에 "is-a 관계"가 있을 때
    예: Animal → Dog, Cat
  • 한 클래스만 상속하면 충분할 때 (단일 상속 구조)
abstract class Animal {
    String name;

    void breathe() {
        System.out.println("숨을 쉰다");
    }

    abstract void sound();
}

인터페이스가 더 적합한 경우

  • 클래스에 특정 기능을 "강제"하고 싶을 때
  • 여러 클래스가 서로 다른 구조지만 같은 기능을 가져야 할 때
  • 이미 다른 클래스를 상속받고 있어서 다중 상속이 필요할 때
interface Flyable {
    void fly();
}

interface Swimmable {
    void swim();
}

class Duck extends Animal implements Flyable, Swimmable {
    public void fly() { ... }
    public void swim() { ... }
}

한눈에 비교

공통 필드와 기능을 함께 제공해야 함 추상 클래스
여러 기능을 조합해야 함 인터페이스
다중 상속이 필요함 인터페이스
공통 부모 타입으로서 역할을 강조하고 싶음 추상 클래스
기능만 선언하고 구현은 위임하고 싶음 인터페이스