클래스
를 설계도에 비유한다면,추상클래스
는 미완성 설계도에 비유할 수 있다. 미완성 설계도로 완성된 제품을 만들 수 없듯이 추상클래스로 인스턴스는 생성할 수 없다. 추상클래스는 상속을 통해서 자손클래스에 의해서만 완성될 수 있다.
추상클래스는 키워드 abstract
를 붙이기만 하면 된다. 이렇게 함으로써 이 클래스를 사용할 때, 클래스 선언부의 abstract를 보고 이 클래스에는 추상메서드가 있으니 상속을 통해서 구현해주어야 한다는 것을 쉽게 알 수 있다.
abstract class 클래스이름{
...
}
추상클래스는 추상메서드
를 포함하고 있다는 것을 제외하고는 일반클래스와 전혀 다르지 않다. 추상클래스에도 생성자가 있으며, 멤버변수와 메서드도 가질 수 있다.
같은 크기의 TV라도 기능의 차이에 따라 여러 종류의 모델이 있지만, 이 들 설계도는 아마 90% 정도는 동일할 것이다. 서로 다른 세 개의 설계도를 따로 그리는 것보다는 공통적인 부분을 그리는 미완성 설계도를 만들어 놓고, 이 미완성 설계도를 이용해서 각각의 설계도를 완성하는 것이 훨씬 효율적이다.
메서드는 선언부
와 구현부
로 구성되어 있다고 했다. 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상메서드이다. (설계만 해놓고 실제 수행될 내용은 작성하지 않았기에 미완성 메서드인 것)
/* 메서드의 기능 목적 */
abstract 리턴타입 메서드이름();
실제 작업내용인 구현부가 없는 메서드가 무슨 의미가 있을까 싶겠지만, 메서드를 작성할 때 구현부보다 더 중요한 부분이 선언부이다.
메서드의 이름, 매개변수, 반환 타입을 결정하는 것은 쉬운 일이 아니기 때문이다.
우선, 여러 클래스에 공통적으로 사용될 수 있는 클래스를 바로 작성해보도록 하자
아래는 Player라는 추상클래스이다. ( 이 클래스는 VCR이나 Audio와 같은 재생 기기를 클래스로 작성할 때, 이들의 조상으로 사용될 수 있다.)
abstract class Player {
boolean pause; // 일시정지 상태를 저장하기 위한 변수
int currentPos; // 현재 play되고 있는 위치를 저장하기 위한 변수
Player() { // 추상클래스도 생성자가 있어야 함
pause = false;
currentPos = 0;
}
abstract void play(int pos); // 추상메서드
abstract void stop(); // 추상메서드
void play() {
play(currentPos);
}
void pause() {
if(pause) {
pause = false;
play(currentPos);
} else {
pause = true;
stop();
}
}
}
이제 Player클래스를 조상으로 하는 MP3Player 클래스를 만들어 보자.
class MP3Player extends Player {
void play(int currentPos) {
/* 조상의 추상메서드를 구현 */
}
void stop() {
/* 조상의 추상메서드를 구현 */
}
int currentAlbum; // 현재 재생중인 앨범
void nextAlbum() {
...
}
void preAlbum() {
...
}
}
이번에는, 기존의 클래스로부터 공통된 부분을 뽑아내어 추상클래스를 만들어 보도록 하자.
class Marine {
int x,y;
void move(int x, int y) {}
void stop() {}
void stimPack() {}
}
class Tank {
int x,y;
void move(int x, int y) {}
void stop() {}
void changeMode() {}
}
class Dropship {
int x,y;
void move(int x, int y) {}
void stop() {}
void unload() {}
}
위의 클래스들로부터 공통 부분을 뽑아내어 하나의 클래스로 만들고, 이를 상속받는 구조를 코드로 작성해보자.
abstract class Unit {
int x,y;
abstract void move(int x, int y);
void stop();
}
/* 각 유닉마다 이동 방식이 다르므로 move()메서드만 따로 구현해준다. */
class Marine extends Unit{
void move(int x, int y) {}
void stimPack() {}
}
class Tank extends Unit{
void move(int x, int y) {}
void changeMode() {}
}
class Dropship extends Unit{
void move(int x, int y) {}
void unload() {}
}