7-3상속(추상 클래스)
객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 한다면 이 클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다.
*추상 클래스가 부모, 실체 클래스가 자식으로 구현되어 실체 클래스는 추상 클래스의 모든 특성을 물려받고, 추가적인 특성을 가질 수 있다. 여기서 특성이란 필드와 메소드를 말한다.
추상 클래스의 용도
1. 공통된 필드와 메소드의 이름을 통일할 목적
실체 클래스를 설계하는 사람이 여러 사람일 경우, 실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있다.
2. 실체 클래스를 작성할 때 시간 절약
공통적인 필드와 메소드는 추상 클래스인 Phone에 모두 선언해두고, 다른 점만 실체 클래스에 선언하면 실체 클래스를 작성하는 데 시간을 절약할 수 있습니다.
추상 클래스 선언
추상 클래스를 선언할 때에는 클래스 선언에 abstract 키워드를 붙여야 한다. abstract를 붙이면 new 연산자를 이용해서 객체를 만들지 못하고, 상속을 통해 자식 클래스만 만들 수 있다.
ex)
public abstract class 클래스 {
//필드
//생성자
//메소드
}
-> 추상 클래스도 일반 클래스와 마찬가지로 필드, 생성자, 메소드 선언을 할 수 있다. new 연산자로 직접 생성자를 호출할 수 없지만 자식 객체가 생성될 때 super()를 호출해서 추상 클래스 객체를 생성하므로 추상 클래스도 생성자가 반드시 있어야 한다.
ex)
추상 클래스
public abstract class Phone {
//필드
public String owner;
//생성자
public Phone(String owner) {
this.owner = owner;
}
//메소드
public void turnOn() {
System.out.println("폰 전원을 켭니다.");
}
public void turnOff() {
System.out.println("폰 전원을 끕니다.");
}
}
실체 클래스
public class SmartPhone extends Phone {
//생성자
public SmartPhone(String owner) {
super(owner);
}
//메소드
public void internetSearch() {
System.out.println("인터넷 검색을 합니다.");
}
}
실행 클래스
public class PhoneExample {
public static void main(String[] args) {
//Phone phone = new Phone();
SmartPhone smartphone = new SmartPhone("홍길동");
smartPhone.turnOn();
smartPhone.internetSearch();
smartPhone.turnOff();
}
}
추상 메소드와 재정의
추상 클래스는 실체 클래스가 공통적으로 가져야 할 필드와 메소드들을 정의해놓은 추상적인 클래스로, 실체 클래스의 멤버(필드, 메소드)를 통일하는 데 목적이 있다.
하지만 메소드의 선언만 통일하고, 실행 내용은 실체 클래스마다 달라야 하는 경우가 있다. 예를 들어, 모든 동물은 소리를 내기 때문에 Animal 추상 클래스에서 sound()라는 메소드를 정의했다고 가정하자. 그렇다면 어떤 소리를 내도록 해야 하는데, 이것은 실체 클래스에서 직접 작성해야 한다. 왜냐하면 동물은 다양한 소리를 내므로 이것을 추상 클래스에서 통일적으로 작성할 수 없기 때문이다. 그렇다고 해서 sound() 메소드를 실체 클래스에서 작성하도록 하면 sound() 메소드를 잊어버리고 작성하지 않을 경우 동물은 소리를 낸다는 것에 위배된다.
이런 경우를 위해서 추상 클래스는 추상 메소드를 선언할 수 있다.
추상 메소드
abstract 키워드와 함께 메소드의 선언부만 있고 메소드 실행 내용인 중괄호 {}가 없는 메소드를 말한다.
ex)
[public | protected] abstract 리턴타입 메소드이름(매개변수, ...);
이렇게 추상 클래스 설계 시 하위 클래스가 반드시 실행 내용을 채우도록 강제하고 싶은 메소드가 있을 경우 해당 메소드를 추상 메소드로 선언한다.
ex)
public abstract class Animal {
public abstract void sound();
}
-> 이렇게 하면 Animal 클래스를 상속하는 하위 클래스는 동물마다 고유한 소리를 내도록 sound() 메소드를 재정의해야 한다.