미완성 메소드를 갖고 있는 클래스
abstract class Player { // 추상클래스(미완성 클래스)
abstract void play(int pos); // 추상메소드(몸통 { } 이 없는 미완성 메소드)
abstract void stop(); // 추상메소드
}
다른 클래스 작성에 도움을 주기 위한 것. 인스턴스 생성 불가
Player p = new Player(); // 에러. 추상클래스의 인스턴스 생성 불가
상속을 통해 추상 메소드를 완성해야 인스턴스 생성가능
// 상속을 통해 완성된 메소드
class AudioPlayer entends Player {
void play(int pos) { /* 내용 생략 */ } // 추상메소드를 구현
void stop() { /* 내용 생략 */ } // 추상메소드를 구현
}
상속된 자손의 메소드를 완성하면
조상타입 Player도 사용가능하다.
Player.p 를 호출해도 자손타입 메소드가 실행된다.
AudioPlayer ap = new AudioPlayer(); // Ok
Player p = new AudioPlayer(); // Ok
abstract 리턴타입 메소드이름();
꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우 사용된다.
abstract class AbstractPlayer extends Player {
void play(int pos) { /* 내용 생략 */ } // 추상메소드를 구현
// abstract void stop(); 도 상속이 됐기 때문에 class 앞에 abstract를 붙여야 함
}
AbstractPlayer class는 Player class에서 받아 2개의 추상 메소드를 상속 받았지만 메소드를 1개밖에 구현하지 않아 abstract class이다. 따라서 class 에 abstract 를 붙여야함.
그렇지 않으면 에러가 발생한다.
필요에 따라서 추상클래스를 상속받아서 추상메소드를 전부 구현해도, 안해도된다.
추상메소드를 호출 할 수 있는 이유는 나중에 상속을 통해서 자손이 완성할 수 있기 때문.
추상클래스라 인스턴스 생성 불가이기 때문에 호출하는 코드가 있어도 호출되지 않음.
상속을 통해 자손이 추상 메소드를 완성하고 자손객체를 생성하면 그 때 호출된다.
public class Ex7_10 {
public static void main(String[] args) {
Unit[] group = { new Marine(), new Tank(), new Dropship() };
// 아래 네개의 코드를 위의 하나의 코드로 줄일 수 있다.
// Unit[] group = new Unit[3];
// group[0] = new Marine();
// group[1] = new Tank();
// group[2] = new Dropship();
for (int i = 0; i < group.length; i++)
group[i].move(100, 200);
}
}
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) {
System.out.println("Marine[x=" + x + ",y=" + y + "]");
}
void stimPack() { /* 스팀팩을 사용한다. */ }
}
class Tank extends Unit { // 탱크
void move(int x, int y) {
System.out.println("Tank[x=" + x + ",y=" + y + "]");
}
void changeMode() { /* 공격모드를 변환한다. */ }
}
class Dropship extends Unit { // 수송선
void move(int x, int y) {
System.out.println("Dropship[x=" + x + ",y=" + y + "]");
}
void load() { /* 선택된 대상을 태운다. */ }
void unload() { /* 선택된 대상을 내린다. */ }
}
공통 부분을 추출해서 Unit 클래스로 정의 ->
나머지 클래스들은 Unit 클래스를 상속 받고 코드들이 간결해짐 (코드의 중복 제거)
// 인터페이스 선언
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메소드이름(매개변수목록);
}
interface PlayingCard {
public static final int SPADE = 4;
final int DIAMOND = 3; // public static final int DIAMOND = 3;
static int HEAR = 2; // public static final int HEART = 2;
int CLOVER = 1; // public static final int CLOVER = 1;
// 상수는 항상 public static final 이라 일부 생략 가능
public abstract String getCardNumber();
String getCardKind(); // public abstract String get CardKind();
// 위와 같이 인터페이스이 추상 메소드는 public abstract 여서 생략 가능
}
interface Fightabl extends Movable, Attackable { }
interface Moveable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
class 클래스이름 implements 인터페이스이름 {
// 인터페이스에 정의된 추상메소드를 모두 구현해야 함
}
예제
interface Fightable {
void move (int x, int y);
void attack (Unit u);
}
class Fighter. implements Fightable {
public void move (int x, int y) { /* 메소드 구현 */ }
public void attack (Unit u) { /* 메소드 구현 */ }
}
// 일부만 구현하는 경우, 클래스 앞에 abstract 를 붙여야 함
abstract class Fighter implements Fightable {
public void move (int x, int y) { /* 메소드 구현 */ }
// public abstract void attack (Unit u);
}