추상 클래스는 부모 클래스는 제공하지만 실제로 객체를 생성할 수 없는 클래스를 의미한다. 추상적인 개념을 제공하는 의미로 객체 생성이 불가능하다.
public abstract class AbstractAnimal {}
부모 클래스를 상속 받는 자식 클래스에서 반드시 오버라이딩 해야하는 메서드를 부모 클래스에 정의할 수 있고, 이를 추상 메서드라고 한다.
public abstract void sound();
예시를 살펴보자. 부모 클래스 AbstractAnimal과 자식클래스들을 구현해보자.

public abstract class AbstractAnimal {
public abstract void sound();
public void move() {
System.out.println("동물이 움직입니다.");
}
}
public class Dog extends AbstractAnimal {
@Override
public void sound() {
System.out.println("멍멍");
}
}
public class Cat extends AbstractAnimal {
@Override
public void sound() {
System.out.println("냐옹");
}
}
public class Cow extends AbstractAnimal {
@Override
public void sound() {
System.out.println("음메");
}
}
// -----------------------main method---------------------------------
public class AbstractMain {
public static void main(String[] args) {
//추상클래스 생성 불가
//AbstractAnimal animal = new AbstractAnimal();
Dog dog = new Dog();
Cat cat = new Cat();
Caw caw = new Caw();
cat.sound();
cat.move();
soundAnimal(cat);
soundAnimal(dog);
soundAnimal(caw);
}
//동물이 추가 되어도 변하지 않는 코드
private static void soundAnimal(AbstractAnimal animal) {
System.out.println("동물 소리 테스트 시작");
animal.sound();
System.out.println("동물 소리 테스트 종료");
}
}
위의 코드에서 컴파일 에러가 발생할 수 있는 경우를 정리해보자.
AbstractAnimal animal = new AbstractAnimal();
//java: poly.ex3.AbstractAnimal is abstract; cannot be instantiated
public class Dog extends AbstractAnimal {
/*
@Override
public void sound() {
System.out.println("멍멍");
}
*/
}
// java: poly.ex3.Dog is not abstract and does not override abstract method sound()in poly.ex3.AbstractAnimal
즉, 결론적으로 추상 클래스는 일반 클래스에 '제약'이 추가된 클래스라고 볼 수 있다. 이를 제외하고는 모든 것이 동일하다. 해당 제약으로 인해 실수로 클래스 객체를 직접 생성하거나 sound()를 오버라이딩 하지 않는 문제를 근본적으로 해결이 가능하다고 볼 수 있다.

위의 AbstractAnimal 추상 클래스를 살펴보면, 추상 메서드인 sound()와 일반 메서드인 move()로 이루어져 있음을 알 수 있다.
순수 추상 클래스란 모든 메서드가 추상 메서드인 추상 클래스를 의미한다.
public abstract class AbstractAnimal {
public abstract void sound();
public abstract void move();
}

순수 추상 클래스는 특별한 로직은 없고 다형성을 위한 껍데기 역할을 한다. 순수 추상 클래스의 모든 메서드는 자식 클래스가 반드시 오버라이딩을 진행해야 하는데 이는 특정 규격을 맞춰 구현하는 과정처럼 느껴진다.
다음 포스팅에서는 순수 추상 클래스를 더 편리하게 사용하기 위한 '인터페이스'에 대해 포스팅 할 예정이다.