본문 바로가기

Java/Java SE, EE

[Java/Java SE, EE] 추상(Abstract) 클래스

추상(Abstract) 클래스

사전적인 의미에서, 추상이란 실체하는 물체의 공통되는 특징을 추출한 것을 말합니다. 예를 들어, 참새와 비둘기는 날아다니며, 알을 낳는다는 추상적인 공통점을 갖습니다.

자바의 클래스에도 추상적인 공통점을 정의하는 추상 클래스가 존재합니다. 객체를 직접 생성하기 위해 정의한 클래스를 실체 클래스라고 부른다면, 추상 클래스는 객체의 공통점을 정의하고 구현하기 위한 목적으로 사용됩니다.

추상 클래스는 다음과 같이 정의 할 수 있습니다.

[접근 제한자 public|protected|default|private] abstract class [클래스 이름] { }

예를 들어, 참새와 비둘기의 추상적인 공통점은 다음과 같이 추상 클래스로 구현 할 수 있습니다.

public abstract class Bird {
   public void Fly() { }	// 새는 날 수 있다
}

추상 클래스는 객체를 생성하기 위해 new 연산자와 함께 사용 될 수 없습니다. 추상 클래스는 다른 파생 클래스로 상속되어 사용됩니다. 따라서 다음과 같은 구문은 잘못되었습니다.

Bird bird = new Bird();		// 추상 클래스는 인스턴싱 불가능

추상 클래스의 장점

그렇다면 추상 클래스는 어떤 이유로 사용되고, 어떤 장단을 갖고 있을까요? 추상 클래스는 추상적인 공통된 특징을 구현하며, 구조적으로 반드시 상속 관계를 갖게된다는 점에서 다음과 같은 장점을 갖고 있습니다.

  • 공통된 필드와 메소드의 이름을 통일
    공통된 멤버를 각 클래스가 별개로 선언하는 것보다, 부모 클래스인 추상 클래스에서 관리하는 것이 통일성 측면에서 유리합니다.
  • 개발성 향상
    공통된 멤버를 중복으로 작성할 필요가 없으므로, 개발 시간이 단축됩니다. 또한 공통된 멤버를 수정할 때도 하나의 클래스만 수정하면 모든 파생 클래스에 적용되므로 유지보수에 유리합니다.
  • 직접적인 사용 방지
    만약 추상 클래스의 역할을 대신하는 부모 클래스를 생성한다고 가정해봅시다. 부모 클래스는 추상적인 공통점만을 갖고 있고, 다른 클래스에 파생되기 위한 붕어빵 틀과 같은 역할을 합니다. 일반적으로 이같은 클래스는 직접 사용되는 것을 목적으로 구현하지 않습니다. 추상 클래스를 사용하면 컴파일러가 직접 사용에 대해서 방지해주므로 이러한 실수를 사전에 예방 할 수 있습니다.
  • 다형성 등
    앞의 여러 특징들 역시 상속 관계에 있는 부모 클래스의 특징들에 속합니다. 마찬가지로, 다형성과 같은 부모 클래스의 특징은 추상 클래스에서도 그대로 적용됩니다.

추상 메소드

우리가 추상 클래스를 정의할 때, 어떤 메소드는 시그니쳐(Signature)만 미리 정의하고 싶을 수 있습니다. 단순히 내부에서 동작하는 로직의 구현을 미루고 싶은 경우일 수도 있고, 또는 부모 클래스의 메소드를 파생된 클래스마다 각각 오버라이딩하고 싶은 경우일 수도 있습니다.

이처럼 메소드의 시그니쳐(접근 제한자, 리턴 타입, 메소드 이름, 매개 변수)만 미리 정의하고, 내부는 구현하지 않는 것을 추상 메소드라고 부릅니다.

[접근 제한자 public|protected|default|private] abstract [리턴 타입] [메소드 이름] ([매개 변수])

추상 메소드는 반드시 추상 클래스에서만 정의할 수 있습니다. 또한 추상 메소드를 정의하고 있는 추상 클래스를 파생하면, 파생된 클래스는 반드시 추상 메소드의 내용을 직접 구현(오버라이딩)하도록 강요됩니다.

public abstract class Bird {
   public abstract void Fly();
}

public class Pigeon extends Bird {
   @Override
   public void Fly() {
      System.out.println("이 메소드는 추상 클래스로부터 정의된 추상 메소드를 구현하고 있습니다.");
   }
}