클래스가 완성된 설계도라면, 추상클래스는 미완성 설계도라고 볼 수 있다.
추상클래스는 선언부에 abstract 키워드만 붙이면 된다.
abstract class 클래스이름 {
...
}
추상클래스는 추상 메서드를 포함하고 있다는 것을 제외하면 일반클래스와 똑같다.
추상클래스에도 생성자가 있으며, 멤버변수와 메서드도 가질 수 있다.
추상클래스는 스스로는 인스턴스가 될 수 없고 상속을 통해서 자식클래스에 의해서만 완성될 수 있다.
추상클래스 자체로는 클래스로서의 역할을 다 하지 못하지만, 새로운 클래스(자식 클래스)를 작성하는데 있어서 바탕이 되는 부모클래스로서 중요한 의미를 갖는다.
새로운 클래스를 작성할 때 아무것도 없이 시작하는 것보다는 어느정도 틀이 갖춰진 상태에서 작성하는게 훨씬 나을 것이기 때문이다.
메서드는 선언부와 구현부로 나뉘어져 있는데, 추상메서드는 선언부만 있고 구현부는 작성하지 않은 채로 남겨둔 것이 추상메서드이다.
abstract class Animal {
// 추상 메서드 선언 방법
// abstract 리턴타입 메서드이름();
abstract void cat(); // 구현부 없음
abstract void dog(); // 구현부 없음
}
추상클래스를 상속받아서 작성되는 클래스는 추상클래스 내의 추상메서드를 전부 오버라이딩해서 자신의 클래스에 맞게 다시 구현해야 한다.
만약 추상메서드 중 하나라도 구현하지 않는다면 자식클래스 역시 추상클래스로 선언해야한다.
// 추상메서드를 모두 오버라이딩 했을 때
class Cat extends Animal {
void cat() {
System.out.println("애옹");
}
void dog() {
System.out.println("멍멍!");
}
}
// 추상메서드 중 하나라도 구현하지 않았을 때
abstract class Cat extends Animal {
void cat() {
System.out.println("애옹");
}
}
사실 구현부에 내용없이 {}만 붙이면 일반 클래스와 다를게 없다.
하지만 이렇게 될 경우 상속받는 클래스들이 메서드가 온전히 구현된것으로 인식하고 오버라이딩을 통해 자신의 클래스에 맞게 다시 구현하지 않을 수도 있다.
그래서 abstract 키워드로 추상클래스임을 정의해놓으면 자식클래스를 작성할 때 메서드의 내용을 구현해줘야 한다는 것을 인식하고 자신의 클래스에 맞게 구현할 것이다.
// 일반 클래스
class Animal {
void cat() { }
}
// 추상 클래스
abstract class Animal {
abstract void cat();
}
추상클래스를 이해하면서 일반클래스를 오버라이딩 하는거랑 똑같지 않나 하는 의문이 들었는데
결국 추상클래스는 자식클래스에서 무조건 정의를 해야하는 메서드가 있다고 판단 됐을 때 자식클래스에서 메서드 구현을 강제하도록 하는게 목적이다!
잘 알아뒀다가 적절한 때에 잘 사용하면 좋겠다는 생각이 든다.