[Java] 추상 클래스 (abstract class)와 추상 메서드(abstract method)의 개념
추상 클래스와 추상 메서드
1) 추상 클래스
- 서브 클래스에게 공통 필드와 메서드를 상속해주는 용도로 사용한다.
- 그 자체로 인스턴스를 만들어 사용하지 않는 경우에
"추상 클래스"로 선언한다.
- 예) Car 클래스는 Sedan, Truck, Bulldozer의 공통 기능을 모아둔 클래스이다.
이 클래스를 직접 사용하려고 만든 것이 아니다.
이와 같이 특히 generalization 과정에 생성된 수퍼 클래스인 경우
주로 추상클래스로 선언한다.
- 왜?
직접 사용하지 말라는 의미이다.
상속 받아 쓰라는 의미이다.
단지 상속 해주는 역할을 한다는 의미이다.
- 실습
- Car 클래스와 Loader 클래스는 직접 사용하기 위해 만든 클래스가 이니다.
서브 클래스의 공통 필드나 메서드를 관리하기 쉽도록 하기 위해 수퍼
클래스로 정의한 것이다.
그래서 이 클래스들은 abstract로 선언하는 것이 마땅하다.
2) 추상 메서드
- 서브 클래스 마다 기능을 다루는 방법이 다를 것 같으면
굳이 수퍼 클래스에서 그 메서드를 정의하지 말라
- 또는 서브 클래스에게 특정 메서드를 반드시 구현하도록 강요(강제)하고 싶다면
수퍼 클래스에서 그 메서드를 정의하지 말라!
- 이런 메서드인 경우,
"추상 메서드"로 선언한다.
- 의미?
- 서버 클래스를 만드는 개발자, 이 메서드를 반드시 구현하세요.
- 서브 클래스를 만드는 개발자, 제가 이 메서드를 구현해 봐야 소용이 없을 것 같습니다.
- 예) Car 클래스의 run() 메서드는 모든 서브 클래스에서 재정의 해야한다.
- 추상 메서드는 추상 클래스 만이 가질 수 있다.
인스턴스가 생성되어 실제 동작되는 클래스는 추상 메서드를 가질 수 없다.
추상 클래스 Car와 추상 메서드 run()의 예제
public abstract class Car {
protected String model;
protected String maker;
protected int cc;
public Car() {
super();
}
public Car(String model, String maker, int cc) {
this.model = model;
this.maker = maker;
this.cc = cc;
}
// 이 메서드느 어차피 서브 클래스에서 무조건 재정의할 것이다.
// 또는 재정의하도록 강제하고 싶다.
// 그렇다면 여기서 코딩하지 말자
// 단지 어떤 메서드인지 선언만 하라!
// 추상 메서드는 구현할 수 없다.
public abstract void run();
}
Car로부터 상속 받은 추상 클래스 Loader의 예제
- 짐을 싣는 메서드를 구현
public abstract class Loader extends Car {
Object storage;
public Loader() {
super();
}
public Loader(String model, String maker, int cc) {
super(model, maker, cc);
}
// 서브 클래스에서도 그냥 사용할 수 없는 메서드라면,
// 다음 메서드와 같이 수퍼 클래스에서 선언한다.
public void load(Object obj) {
this.storage = obj;
System.out.printf("%s를 실었습니다.\n", obj);
}
}
Loader로부터 상속 받은 일반 클래스 Sedan의 예제
- Car의 추상 메서드 run()을 오버라이딩한다.
public class Sedan extends Loader {
boolean auto;
public Sedan(String model, String maker, int cc, boolean auto) {
super(model, maker, cc);
this.auto = auto;
}
// 상속 받은 메서드를 서브 클래스의 역할에 맞게끔 재정의하자! 오버라이딩
public void run() {
System.out.println("부웅~~ 부드럽게 달린다.");
}
}
Loader로부터 상속 받은 일반 클래스 Truck의 예제
- Car의 추상메서드 run()과 Loader의 일반메서드 load()를 오버라이딩 한다.
public class Truck extends Loader {
public Truck(String model, String maker, int cc) {
super(model, maker, cc);
}
// 수퍼 클래스 Car의 run()을 오버라이딩 한다.
public void run() {
System.out.println("부왕~~ 힘차게 달린다.");
}
// 수퍼 클래스 Loader의 load()를 오버라이딩 한다.
public void load(Object obj) {
if (obj != null) {
super.load(obj);
} else {
System.out.println("비었습니다.");
}
}
public void dump() {
if (storage != null) {
System.out.printf("%s를 내렸습니다.\n", this.storage);
this.storage = null;
} else {
System.out.println("내릴 게 없습니다.");
}
}
}
* 결론!
- 추상 메서드는 추상 클래스 만이 가질 수 있다.
인스턴스가 생성되어 실제 동작되는 클래스는 추상 메서드를 가질 수 없다.
- 추상 클래스는 어디까지나 유지보수를 하게 될 개발자에게 자식 클래스에서
메서드를 재정의하길 바라는 마음에서, 만들어진 문법이다.