클래스를 설계도에 비유한다면, 추상클래스는 미완성 설계도에 비유할 수 있다. 미완성 설계도란, 단어의 뜻 그대로 완성되지 못한 채로 남겨진 설계도를 말한다. 클래스가 미완성이라는 것은 멤버의 개수에 관계된 것이 아니라, 단지 미완성 메서드(추상메서드)를 포함하고 있다는 의미이다.
미완성 설계도로 완성된 제품을 만들 수 없듯이 추상클래스로 인스턴스는 생성할 수 없다. 추상클래스는 상속을 통해서 자손클래스에 의해서만 완성될 수 있다.
추상클래스 자체로는 클래스로서의 역할을 다 못하지만, 새로운 클래스를 작헝하는데 있어서 바탕이 되는 조상클래스로서 중요한 의미를 갖는다. 새로운 클래스를 작성할 때 아무 것도 없는 상태에서 시작하는 것보다는 완전하지는 못하더라도 어느 정도 틀을 갖춘 상태에서 시작하는 것이 나을 것이다.
추상클래스는 키워드 'abstract'를 붙이기만 하면 된다. 이렇게 함으로써 이 클래스를 사용할 때, 클래스 선언부의 abstract를 보고 이 클래스에는 추상메서드가 있으니 상속을 통해서 구현해 주어야 한다는 것을 쉽게 알 수 있을 것이다.
abstract가 사용될 수 있는 곳 - 클래스, 메서드
추상 클래스는 아직 완성되지 않은 메서드가 존재하는 '미완성 설계도'이므로 인스턴스를 생성할 수 없다.
abstract class AbstractTest { // 추상 클래스 (추상 메서드를 포함한 클래스)
abstract void move(); // 추상 메서드 (구현부가 없는 메서드)
}
추상클래스는 추상메서드를 포함하고 있다는 것을 제외하고는 일반클래스와 전혀 다르지 않다. 추상클래스에도 생성자가 있으며, 멤버변수와 메서드도 가질 수 있다.
꽤 드물지만 추상 메서드가 없는 클래스, 즉 완성된 클래스도 abstract를 붙여서 추상 클래스로 만드는 경우도 있다. 예를 들어, java.awt.event.WindowAdapter는 아래와 같이 아무런 내용이 없는 메서드들만 정의되어 있다. 이런 클래스는 인스턴스를 생성해봐야 할 수 있는 것이 아무것도 없다. 그래서 인스턴스를 생성하지 못하게 클래스 앞에 제어자 'abstract'를 붙여 놓은 것이다.
public abstract class WindowAdapter
implemets WindowListener, WindwStateListener, WindowFocusListener {
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
...
이 클래스 자체로는 쓸모가 없지만, 다른 클래스가 이 클래스를 상속받아서 일부의 원하는 메서드만 오버라이딩해도 된다는 장점이 있다. 만일 이 클래스가 없다면 아무런 내용도 없는 메서드를 잔뜩 오버라이딩해야 한다.
선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상메서드이다. 즉, 설계만 해 놓고 실제 수행될 내용은 작성하지 않았기 때문에 미완성 메서드 인것이다.
메서드를 이와 같이 미완성 상태로 남겨 놓는 이유는 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문에 조상 클래스에서는 선언부만을 작성하고, 주석을 덧붙여 어떤 기능을 수행할 목적으로 작성되었는지 알려 주고. 실제 내용은 상속받는 클래스에서 수현하도록 비워 두는 것이다.
추상메서드 역시 키워드 'abstract'를 앞에 붙여 주고, 추상메서드는 구현부가 없으므로 괄호 대신 문장의 끝을 알리는 ';'을 적어준다.
/* 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지 설명한다. */
abstract 리턴타입 메서드이름();
추상클래스로부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상메서드를 모두 구현해주어야 한다. 만일 조상으로부터 상속받은 추상메서드 중 하나라도 구현하지 않는다면, 자손클래스 역시 추상클래스로 지정해 주어야 한다.
abstract class Player {
abstract void play(int pos); // 추상메서드
abstract void stop(); // 추상메서드
}
class AudioPlayer extends Player {
void play(int pos) { // 추상메서드를 구현
/* 내용 생략 */
}
void stop() { // 추상메서드를 구현
/* 내용 생략 */
}
}
abstract class AbstractPlayer extends Player {
void play(int pos) { // 추상메서드를 구현
/* 내용 생략 */
}
}
일반 메서드와 추상메서드의 차이
public abstract class Shape { // 추상 클래스 선언
double pi = 3.14;
abstract void draw(); // 추상 메서드
public double findArea() { // 일반 메서드
return 0.0;
}
}