결론부터 말씀드리면, 추상 클래스(abstract class)의 객체는 직접 생성할 수 없습니다. 하지만 추상 클래스 타입의 참조 변수(reference variable)는 선언할 수 있으며, 이 참조 변수는 해당 추상 클래스를 상속받은 파생 클래스(하위 클래스)의 객체를 가리키는 용도로 활용됩니다.
추상 클래스란 구체적인 구현 내용은 감추고, 메서드의 정의(시그니처)만 외부에 보여주는 클래스를 의미합니다. 자바에서 추상 클래스는 기본 동작을 구현한 인스턴스 메서드를 포함할 수 있으며, 요구사항이 어느 정도 명확하고 부분적인 구현이 필요한 경우에 추상 클래스를 선택하는 것이 좋은 설계 방식입니다.
추상 클래스의 주요 특징
- new 키워드를 사용해 인스턴스화할 수 없습니다.
- 추상 메서드(구현부가 없는 메서드)를 하나 이상 포함할 수 있습니다.
- 필드, 생성자, 일반 메서드를 함께 가질 수 있습니다.
- 하위 클래스는 추상 메서드를 반드시 오버라이드해야 합니다.
예제 코드
abstract class Diagram {
double dim1;
double dim2;
Diagram(double a, double b) {
dim1 = a;
dim2 = b;
}
// area()는 이제 추상 메서드입니다.
abstract double area();
}
class Rectangle extends Diagram {
Rectangle(double a, double b) {
super(a, b);
}
// 사각형을 위한 area() 재정의
double area() {
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
}
class Triangle extends Diagram {
Triangle(double a, double b) {
super(a, b);
}
// 삼각형을 위한 area() 재정의
double area() {
System.out.println("Inside Area for Triangle.");
return dim1 * dim2 / 2;
}
}
public class Test {
public static void main(String args[]) {
// Diagram d = new Diagram(10, 10); // 이제 허용되지 않음 (컴파일 오류)
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
Diagram diagRef; // 문제없음, 객체가 생성되지 않음
diagRef = r;
System.out.println("Area of Rectangle is: " + diagRef.area());
diagRef = t;
System.out.println("Area of Triangle is:" + diagRef.area());
}
}위 예제에서 Diagram 타입의 객체는 생성할 수 없지만, Diagram 타입의 참조 변수는 선언할 수 있습니다. 여기서는 Diagram 타입의 참조 변수 diagRef를 만든 뒤, 이 변수가 Rectangle과 Triangle 클래스의 객체를 차례대로 가리키도록 했습니다. 참조 변수가 어떤 객체를 가리키느냐에 따라 각 하위 클래스에서 오버라이드된 area() 메서드가 호출되는데, 이것이 바로 동적 메서드 디스패치(dynamic method dispatch), 즉 다형성(polymorphism)의 대표적인 동작 방식입니다.
실행 결과
Inside Area for Rectangle. Area of Rectangle is: 45.0 Inside Area for Triangle. Area of Triangle is:40.0