정의
- 객체 지향 프로그래밍에서 공통 기능을 정의하되, 일부 메서드의 구체적인 구현은 상속받은 자식 클래스에서 하도록 강제할 때 사용하는 클래스
- 메서드와 오버라이딩을 통해 확장성과 유연성을 제공하여 다형성을 지원함
- abstract 키워드를 통해 선언하며, 추상 메서드와 일반 메서드를 모두 포함할 수 있음
- 자식 클래스는 추상 메서드를 오버라이딩하여 구현해야 함
- 다형성을 통해 부모(추상클래스) 타입으로 자식 객체를 참조하면서 자식 클래스의 오버라이딩된 메서드 사용 가능 👉 예시 참조
예시
public abstract class Animal {
// 일반 메서드
public void breathe() {
System.out.println("동물이 숨을 쉽니다.");
}
// 추상 메서드
public abstract void sound(); // 구현 없이 선언만 존재
}
추상클래스 Animal 안에
추상메서드 sound()
일반메서드 breathe()가 모두 포함
👉 추상 클래스는 일반 메서드와 추상 메서드를 모두 가질 수 있음
추상 메서드와 오버라이딩
위 예시를 참고하여 설명하자면,
자식 클래스에서 추상 클래스의 추상 메서드를 오버라이딩하여 구현하게 됨
-> 다양한 동물 종류에 따라 sound() 메서드의 동작을 다르게 정의할 수 있음
public class Dog extends Animal {
// sound 메서드를 오버라이딩하여 강아지 소리를 출력
@Override
public void sound() {
System.out.println("멍멍!");
}
}
public class Cat extends Animal {
// sound 메서드를 오버라이딩하여 고양이 소리를 출력
@Override
public void sound() {
System.out.println("야옹!");
}
}
Dog와 Cat 클래스는 Animal 클래스의 sound() 메서드를 오버라이딩하여 각각의 소리를 출력함
= 자식 클래스임.
@Override 애너테이션을 사용해 추상 메서드를 재정의하며, 이걸 통해 컴파일러 의도대로 메서드가 오버라이딩되는지 확인함
활용
추상클래스는 다형성을 구현하는 데 매우 유용하며, 이 다형성을 통 부모 클래스 타입으로 자식 클래스를 다룰 수 있음.
공통된 인터페이스를 제공하면서 구체적인 구현은 자식 클래스에 위임할 수 있음
public class AnimalTest {
public static void main(String[] args) {
Animal dog = new Dog(); // Animal 타입으로 Dog 인스턴스 생성
Animal cat = new Cat(); // Animal 타입으로 Cat 인스턴스 생성
dog.sound(); // 멍멍!
cat.sound(); // 야옹!
}
}
여기서 dog와 cat 변수는 추상클래스인 Animal 타입이지만, 각각 Animal의 자식 클래스인 Dog와 Cat 객체를 참조하고 있음.
sound() 메서드를 호출하면 자식 클래스에서 오버라이딩된 메서드가 각각 실행됨
인터페이스와의 차이점
| 분류 |
추상 클래스 |
인터페이스 |
| 공통점 |
자식 클래스에서 구현을 강제함 |
| 다중상속 |
불가능 |
가능 |
| 통일성 |
클래스의 그룹화 구조적 연관성 있으면서 부분적 개별 구현 허용 |
구현체를 자유롭게 교체 가능해서 결합도를 낮춤 구현에 상관없이 일관된 동작을 수행하게 함 |
| 일반 메서드, 필드 보유 |
가능 |
Java 8 이전까지는 불가능했음 (현재 메서드는 다양하게 보유 가능하나, 필드는 public static final 상수만 가질 수 있음) |
| 적합한 영역 |
상속 구조 내에서 공통된 구현 로직이 필요하고, 여러 클래스가 동일한 기초 구조를 공유할 때 |
공통된 행동을 강제하고, 여러 클래스가 같은 행동을 따르게 하고 싶을 때 |
비고
1. 사용하면서도 정확히 설명하기 어려웠던 개념이 명확해졌다.
레퍼런스
1. 멘토링 강의
2. 구글링, 코드 예시의 경우 ChatGPT