Menu

자바 추상 클래스: abstract 키워드 설명

자바 추상 클래스란 무엇인지, 추상 메서드를 선언하는 방법, 왜 인스턴스화할 수 없는지, 그리고 인터페이스 대신 추상 클래스를 선택해야 할 때를 설명합니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

추상 클래스란

인터페이스는 상태 없이 동작을 선언합니다. 일반 클래스는 완전히 구현되어 있어 인스턴스화할 수 있습니다. 추상 클래스는 그 둘 사이에 위치합니다. 일반 클래스처럼 필드, 생성자, 완성된 메서드를 가질 수 있지만, 일부 메서드를 구현하지 않은 채 남겨둘 수도 있고 직접 인스턴스화하는 것을 금지합니다. abstract 키워드로 표시합니다.

핵심 아이디어는 서브클래스들이 공통으로 가지는 모든 것을 한곳에 모으면서, 각 서브클래스가 실제로 달라지는 부분은 직접 채우도록 강제하는 것입니다.

Animal은 모든 서브클래스를 위해 getName()을 한 번만 정의하고, sound()abstract로 선언합니다. 이는 시그니처는 있지만 본문이 없는 메서드로, Dog가 반드시 제공해야 합니다.

추상 클래스는 인스턴스화할 수 없다

추상 클래스에는 완성되지 않은 메서드가 있을 수 있으므로, 그것을 직접 생성하면 불완전한 객체가 남게 됩니다. 컴파일러는 이를 거부합니다.

Animal a = new Animal("???");   // error: Animal is abstract; cannot be instantiated

항상 구체 서브클래스, 즉 모든 추상 메서드를 구현한 서브클래스를 인스턴스화합니다. 그 서브클래스 인스턴스는 추상 타입의 변수에 담을 수 있으며, 이것이 바로 추상화를 사용하는 방식입니다.

추상 메서드는 서브클래스가 결정하도록 강제한다

abstract 메서드는 서브클래스가 반드시 지켜야 할 약속입니다. 서브클래스가 그중 하나의 구현을 잊으면 그 서브클래스 자체가 추상이 되고, 컴파일러가 이를 알려줍니다. 이것이 추상 클래스의 가장 중요한 지렛대입니다. 특정 동작이 존재함을 보장하면서도 그것이 무엇을 하는지는 지시하지 않습니다.

describe()Shape에 한 번만 작성되어 있지만, 각 서브클래스 고유의 area()를 호출합니다. 추상 클래스는 공통 골격을 제공하고, 서브클래스는 구체적인 내용을 제공합니다.

공유 상태와 생성자

전통적인 인터페이스와 달리, 추상 클래스는 인스턴스 필드를 가질 수 있고 생성자를 정의할 수 있습니다. 생성자가 단독으로 Animal이나 Shape를 만드는 일은 결코 없습니다. 서브클래스가 생성될 때 super(...)를 통해 실행되어 공유 상태를 초기화합니다.

balance 필드, deposit, applyInterest는 한곳에 모여 있습니다. 실제로 달라지는 정책인 interestRate()만 추상으로 남습니다. 서브클래스의 생성자는 이 상속된 상태를 초기화하기 위해 반드시 super(...)를 호출해야 합니다.

함정: abstract와 final 섞기

abstractfinal은 정반대입니다. abstract 메서드는 오버라이드를 요구하고, final 메서드는 그것을 금지합니다. 같은 것에 두 가지를 모두 표시하거나, 추상 클래스를 final로 만드는 것은 컴파일 오류입니다. 또한 추상 클래스가 추상 메서드를 하나도 갖지 않아도 된다는 점을 기억하세요. 인스턴스화를 막기 위한 목적만으로 클래스를 abstract로 선언하는 것은 적법하며, 오로지 상속만을 의도한 기반 타입에 때때로 유용합니다.

abstract final class Bad { }        // error: abstract and final conflict

abstract class Base {
    abstract final void f();        // error: an abstract method can't be final
}

추상 클래스와 인터페이스

둘은 겹치는 부분이 있으므로, 선택은 무엇을 공유해야 하는지에 달려 있습니다.

  • 추상 클래스 - 상태와 코드를 공유하는 밀접하게 관련된 클래스에 사용합니다. SavingsChecking은 모두 Account를 상속해 balance 필드와 deposit 로직을 물려받습니다. 클래스는 하나만 상속합니다.
  • 인터페이스 - 서로 관련 없는 클래스가 공유할 수 있는 기능에 사용합니다. BirdAirplane은 어떤 구현도 공유하지 않으면서 둘 다 Flyable이 될 수 있습니다. 클래스는 여러 개를 구현할 수 있습니다.

흔한 패턴은 둘을 결합합니다. 인터페이스가 계약을 정의하고, 추상 클래스가 상용구 코드를 구현하여, 구체 서브클래스는 고유한 부분만 채우면 됩니다.

다음: 다형성

위의 모든 예제에서 우리는 서브클래스 인스턴스를 추상 타입의 변수에 담은 뒤, 메서드를 호출하면 자동으로 서브클래스의 동작을 얻었다는 점에 주목하세요. 바로 이 한 가지 능력 — 하나의 참조 타입, 런타임에서의 여러 동작 — 이 다형성이며, 추상 클래스와 인터페이스가 진가를 발휘하게 하는 것입니다. 그것이 다음 페이지의 주제입니다.

자주 묻는 질문

자바에서 추상 클래스란 무엇인가요?

추상 클래스는 abstract 키워드로 선언되어 그 자체로는 인스턴스화할 수 없는 클래스입니다. 상속(extend)되도록 설계되어 있습니다. 완전히 구현된 메서드와 필드(서브클래스를 위한 공유 상태와 코드)를 본문이 없는 abstract 메서드와 함께 둘 수 있으며, 후자의 구현은 각 서브클래스의 책임이 됩니다.

자바에서 추상 클래스를 인스턴스화할 수 있나요?

아니요. new AbstractType()은 컴파일 오류입니다. 추상 클래스에는 구현되지 않은(abstract) 메서드가 있을 수 있어 객체가 불완전해지기 때문입니다. 모든 추상 메서드를 채운 구체(concrete) 서브클래스를 인스턴스화한 뒤, 그것을 추상 타입의 변수에 저장합니다.

자바에서 추상 클래스와 인터페이스의 차이는 무엇인가요?

추상 클래스는 인스턴스 필드, 생성자, 부분적으로 구현된 로직을 가질 수 있지만, 클래스는 하나만 상속할 수 있습니다. 인터페이스는 인스턴스 상태 없이 동작을 선언하며, 클래스는 여러 개를 구현할 수 있습니다. 밀접하게 관련된 서브클래스 사이에서 상태와 코드를 공유하려면 추상 클래스를, 서로 관련 없는 클래스에 공통 기능을 부여하려면 인터페이스를 사용하세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기