추상클래스
추상클래스란?
미완성 메서드를 포함하고 있는 미완성 설계도이다. 추상 클래스로는 인스턴스를 생성할 수 없다. 다만 새로운 클래스를 작성하는 데 있어서 바탕이 되는 조상 클래스로 미가 있다. 추상 클래스는 추상 메서드를 포함하고 있다는 것을 제외하고는 일반 클래스와 다르지 않다. 생성자, 멤버변수, 메서드를 가질 수 있다.
한편 추상 메서드가 없는 완성된 클래스라해도 추상 클래스로 지정할 수 있다. 이 경우 인스턴스를 생성할 수 없게 만든다는 의미가 있다.
추상메서드
선언부만 작성하고 구현부는 작성하지 않은 채로 남겨두는 메서드이다. 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있을 경우 조상 클래스에서 추상 메서드로 선언하고 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지만 알려주고 실제 내용은 상속 받는 클래스에서 구현하도록 비워 둔다.
추상 클래스로부터 상속 받은 자손 클래스는 오버라이딩을 통해 조상인 추상클래스의 추상메서드를 모두 구현해주어야 한다. 그렇지 않으면 자손 클래스 또한 추상 클래스가 된다.
메서드를 작성할 때 구현부보다 더 중요한 부분이 선언부(메서드 이름, 작업에 필요한 매개변수, 작업의 결과인 리턴타입)이다. 메서드를 사용할 때는 선언부만 알면 되므로 내용이 없을 지라도 추상메서드를 사용하는 코드를 작성하는 것이 가능하며, 자손 클래스에 구현된 완성된 메서드가 호출되도록 할 수 있다.
추상클래스의 작성
- 추상화: 클래스간의 공통점의 찾아내어 공통 조상을 만드는 작업
- 구체화: 상속을 통해 클래스를 구현, 확장하는 작업
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
abstract class Player {
boolean pause;
int currentPos;
Player() {
pause = false;
currentPos = 0;
}
/** 지정된 위치(pos)에서 재생을 시작하는 기능이 수행하도록 작성*/
abstract void play(int pos);
/** 재생을 즉시 멈추는 기능을 수행하도록 작성*/
abstract void stop();
void play() {
play(currentPos); //추상메서드 사용 가능
}
void pause() {
if(pause) {
pause = false;
play(currentPos);
} else {
pause = true;
stop();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CDPlayer extends Player {
void play(int currentPos) {}
void stop(){}
int currentTrack;
void nextTrack() {
currentTrack++;
//..
}
void preTrack() {
if(currentTrack > 1)
currentTrack--;
//..
}
}
{}
를 비워두고 선언하면 될 텐데 왜 굳이 abstract를 붙여서 추상메서드로 선언할까? 자손 클래스에서 추상메서드를 반드시 구현하도록 강요하기 위해서이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
abstract class Unit {
int x, y;
abstract void move(int x, int y);
void stop(){}
}
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 load(){}
void unload(){}
}
Unit을 추상클래스로 선언하고 각 클래스에서 상속받게 한 덕분에 move() overriding을 강제하고, 변수 x, y와 stop()을 중복해서 작성하지 않아도 된다. 뿐만 아니라 공통조상인 Unit 클래스 타입의 참조변수 배열을 통해서 서로 다른 종류의 인스턴스를 배열로 다룰 수 있다. 또한 후에 각 객체를 사용하는 메서드를 작성한다면, Unit 타입의 파라미터를 가진 메서드를 통해 각 객체를 아규먼트로 넘겨서 작업할 수 있다.