class Vehicle{
private int posX, posY;
public void move(int posX, int posY){
System.out.printf("%X, %Y로 이동%n", posX, posY);
}
public void stop() {
System.out.println("멈춰");
}
public void refuel() {
System.out.println("주유한다");
}
}
class Car extends Vehicle{
public void refuel(){
System.out.println("가솔린을 넣습니다");
}
}
class ElectricCar extends Vehicle{
public void refuel(){
System.out.println("전기를 충전합니다.");
}
}
위와 같은 코드가 있다고 가정하자
Vehicle이라는 부모 클래스를 Car와 ElectircCar가 상속받는다.
refuel 메소드는 오버라이딩 하는 모습을 볼 수 있다.
이 상황에서 우리는
public class Test {
public static void main(String[] args) {
Vehicle [] vec = {new Car(), new ElectricCar()};
for(int i = 0; i < vec.length; i++) {
int posX = (int)(Math.random()*10) + 1;
int posY = (int)(Math.random()*10) + 1;
vec[i].move(posX, posY);
vec[i].refuel();
vec[i].stop();
}
}
}
이런식으로 사용할 수 있을것이다.
그러나.. 한가지 의문이 생긴다..
Vehicle 클래스의 refuel메소드는 정작 사용하지 않고
클래스 ElectricCar, Car 등에서 상속받아 사용한다는 것이다.
이런 상황에서 굳이 부모클래스인 Vehicle에 refuel메소드를 그대로 구현해 놓을 필요가 있을까?
어차피 다 자식 클래스에서 오버라이딩해서 사용하는데...
혹자는 이렇게 말할것이다..
"그냥 refuel메소드를 vehicle에서 지워버리면 안됨?"
그래도 물론 된다. 굳이 ElectricCar, Car 클래스가 refuel메소드를 오버라이딩하는 대신
직접 본인이 구현해서 사용하면 문제될것이 없다.
허나
Vehicle [] vec = {new Car(), new ElectricCar()};
vec[0].refuel();
vec[1].refuel();
이러한 접근이 불가능해진다.
우리는 그동안 다형성을 이용해
Vehicle 타입 참조변수에서 Car객체와 Electirc객체의 오버라이딩 된
refuel()메소드를 사용했는데 (이것을 동적바인딩이라고 부른다)
Vehicle 클래스에 refuel 메서드를 지워버리면
불가능해져버린다.
즉 자손 클래스에서 반드시 재정의 해서 사용하기 때문에
조상 클래스에서 구현한것이 사용될일 없는 메서드를
Abstract 메서드로 구현하면 되는것이고
그 Abstract 메서드가 클래스 내에 하나라도 존재한다면
그 클래스는 Abstract 클래스가 된다.
Abstract 메서드는 메서드의 선언부만 남기고 구현부는 세미콜론으로 대체한다.
그리고 메서드 선언부 부분에 abstract 키워드를 추가한다.
마찬가지로 Abstract 클래스에서도 선언부에 abstract 키워드를 추가해야한다.
Abstract 클래스의 특징
- 당연히 구현부가 없는 abstract 메서드를 가지고 있으므로
객체 생성이 불가능하다.
- 하지만 조상 클래스 타입으로 자식 클래스 참조 가능하다. (다형성의 성질은 남아있음)
- 만약 자식 클래스가 조상 abstract 클래스에서 상속받은 abstract 메서드를 오버라이딩하지
않은 경우에 마찬가지로 자식 클래스도 abstract 클래스가 되며 객체 생성이 불가능하다.
- 구현을 강제할 수 있다. (자식클래스가 abstract 조상 클래스의 abstract 메서드를 강제로 구현해야함, 안그러면 자식클래스에서 객체 생성시 에러 & 자식클래스에 abstract 키워드를 추가하지 않을시 에러남)
그럼 위에 예제를 abstract 클래스 기법을 적용해보면 아래와 같다.
abstract class Vehicle{ private int posX, posY; public void move(int posX, int posY){ System.out.printf("%X, %Y로 이동%n", posX, posY); } public void stop() { System.out.println("멈춰"); } public abstract void refuel(); } class Car extends Vehicle{ public void refuel(){ System.out.println("가솔린을 넣습니다"); } } class ElectricCar extends Vehicle{ public void refuel(){ System.out.println("전기를 충전합니다."); } }