티스토리 뷰
Java 추상 클래스(Abstract Class)와 추상 메서드(Abstract Method)의 구조적 이해
추상 클래스의 본질과 일반 클래스와의 비교
Java에서 추상 클래스(Abstract Class)는 “공통된 특징을 가진 여러 클래스의 기본 틀”입니다.
하지만 이 틀은 완성되지 않은 상태이기 때문에 객체를 직접 생성할 수 없습니다.
즉, 추상 클래스는 “공통점은 미리 정의하고, 세부 내용은 나중에 자식이 채우게 하는 클래스”입니다.
먼저 일반 클래스를 생각해보면 이해가 쉽습니다.
일반 클래스는 모든 기능이 완전히 구현되어 있으므로, 바로 객체를 생성할 수 있습니다.
public class Dog {
public void sound() {
System.out.println("멍멍");
}
}
Dog dog = new Dog();
dog.sound();
출력:
멍멍
위의 예시는 완성된 형태입니다.
Dog는 모든 동작이 정의되어 있기 때문에 바로 사용할 수 있습니다.
하지만 “동물”이라는 더 넓은 개념을 생각해봅시다.
동물이라는 단어에는 “움직인다”, “소리를 낸다” 등의 공통점이 있습니다.
그렇다고 해서 “모든 동물은 똑같이 소리를 낸다”고 말할 수는 없습니다.
이럴 때 추상 클래스가 등장합니다.
추상 클래스의 선언과 의미
추상 클래스는 abstract 키워드를 이용해 선언합니다.
public abstract class Animal {
public void breathe() {
System.out.println("숨을 쉽니다.");
}
}
이 코드는 Animal이란 개념을 정의했지만,
아직 어떤 구체적인 동물인지 명확하지 않습니다.
즉,
breathe()라는 공통 기능은 정의되어 있습니다.- 하지만 어떻게 움직이는지, 어떤 소리를 내는지는 정의되어 있지 않습니다.
이 상태에서는 Animal 객체를 직접 만들 수 없습니다.
다음 코드처럼 하면 오류가 발생합니다.
Animal a = new Animal(); // 오류 발생
그 이유는 Animal이 “완성된 클래스”가 아니기 때문입니다.
추상 클래스만 있는 경우: 공통 기능의 제공
현재 Animal은 “숨을 쉰다”라는 공통 기능만 제공합니다.
즉, 모든 동물이 공통으로 가져야 할 기능을 미리 구현해둔 상태입니다.
이렇게 하면 다른 클래스가 Animal을 상속받을 때,
굳이 숨 쉬는 기능을 다시 만들 필요가 없습니다.
public class Dog extends Animal { }
Dog dog = new Dog();
dog.breathe();
출력:
숨을 쉽니다.
이 경우 자식 클래스 Dog는
부모의 기능을 그대로 물려받아 사용할 수 있습니다.
즉, “모든 동물이 숨을 쉰다”라는 공통된 성질이 상속을 통해 유지됩니다.
하지만 여기에는 한 가지 한계가 있습니다.
“모든 동물이 숨을 쉬긴 하지만, 각자의 방식으로 움직인다”는 점이 구현되지 않았습니다.
이제 바로 이 지점을 해결하기 위해 추상 메서드가 등장합니다.
추상 메서드의 등장: 미완성 행동의 선언
추상 클래스는 단지 공통 기능만 담는 것이 아니라,
“자식 클래스가 반드시 구현해야 하는 기능”을 추상 메서드(abstract method)로 선언할 수 있습니다.
예를 들어,
모든 동물이 움직이긴 하지만 그 방식이 다르다면
부모 클래스에서 “움직여야 한다”는 규칙만 정하고,
실제 “어떻게 움직일지”는 자식이 구현하도록 남겨둘 수 있습니다.
public abstract class Animal {
public void breathe() {
System.out.println("숨을 쉽니다.");
}
public abstract void move();
}
여기서 move()는 추상 메서드입니다.
즉, “모든 동물은 반드시 move 기능을 가져야 한다”는 약속만 정의된 것입니다.
하지만 내용이 없기 때문에 자식이 이 약속을 지켜서 직접 구현해야 합니다.
추상 메서드가 없는 경우와의 비교
먼저, 추상 메서드가 없는 추상 클래스는
자식 클래스에게 구현을 강제하지 않습니다.
public abstract class Animal {
public void breathe() {
System.out.println("숨을 쉽니다.");
}
}
이 경우 자식 클래스는 단순히 기능을 물려받을 뿐,
특별히 추가 구현을 요구받지 않습니다.
public class Bird extends Animal { }
Bird bird = new Bird();
bird.breathe();
출력:
숨을 쉽니다.
즉, “공통 기능을 물려주는 역할만 하는” 추상 클래스입니다.
하지만 추상 메서드가 추가되면 상황이 완전히 달라집니다.
추상 메서드가 포함된 추상 클래스
이제 move()라는 추상 메서드를 추가한 예시를 보겠습니다.
public abstract class Animal {
public void breathe() {
System.out.println("숨을 쉽니다.");
}
public abstract void move();
}
이제 이 클래스를 상속받는 자식은 move()를 반드시 구현해야 합니다.
그렇지 않으면 컴파일 에러가 발생합니다.
public class Dog extends Animal {
@Override
public void move() {
System.out.println("강아지가 걷습니다.");
}
}
public class Bird extends Animal {
@Override
public void move() {
System.out.println("새가 납니다.");
}
}
Animal d = new Dog();
Animal b = new Bird();
d.breathe();
d.move();
b.breathe();
b.move();
출력:
숨을 쉽니다.
강아지가 걷습니다.
숨을 쉽니다.
새가 납니다.
이제 부모 클래스는 “모든 동물은 숨을 쉬어야 하고, 움직일 수 있어야 한다”고 정의했고,
자식 클래스는 “자신만의 움직임 방식”을 구현했습니다.
즉, 추상 클래스는 “공통된 기본 틀”을 제공하고,
추상 메서드는 “각자 다른 세부 동작”을 강제하는 구조를 만듭니다.
추상 메서드가 아닌 메서드와의 비교
추상 메서드는 내용이 없는 “약속”이라면,
일반 메서드는 이미 내용이 있는 “구체적인 기능”입니다.
다음 두 코드를 비교해보면 차이가 명확합니다.
① 일반 메서드 (이미 구현되어 있음)
public void move() {
System.out.println("움직입니다.");
}
→ 모든 자식 클래스가 똑같이 “움직입니다.”를 출력함.
→ 각자 다른 방식으로 표현할 수 없음.
② 추상 메서드 (내용 없음)
public abstract void move();
→ 부모가 “반드시 move 기능을 가져라”라고만 정함.
→ 자식이 스스로 “걷는다”, “난다”, “헤엄친다”로 구체화함.
즉, 추상 메서드는 자율성을 허락하면서도 규칙을 강제하는 장치입니다.
추상 클래스의 확장 구조 정리
| 단계 | 구성 요소 | 설명 |
|---|---|---|
| 1단계 | 일반 클래스 | 모든 기능이 완성된 클래스 (객체 생성 가능) |
| 2단계 | 추상 클래스만 있는 상태 | 일부 공통 기능만 제공, 객체 생성 불가, 구현 강제 없음 |
| 3단계 | 추상 클래스 + 추상 메서드 | 공통 기능 + 자식이 반드시 구현해야 할 기능 강제 |
즉, 추상 클래스는 처음엔 “공통 기능을 모으는 용도”로 시작하고,
필요해지면 “자식이 반드시 구현해야 하는 기능”까지 추가함으로써
더 견고한 구조로 확장됩니다.
결론
- 추상 클래스는 공통된 구조를 정의하지만 미완성인 클래스입니다.
- 추상 메서드는 내용이 없는 메서드로, 자식 클래스가 반드시 구현해야 합니다.
- 추상 클래스만 있을 때는 “공통 기능의 상속”에 집중되고,
객체를 직접 만들 수 없고, 자식이 상속받아 완성해야 합니다.
이를 통해 “같은 이름의 기능을 각기 다르게 구현”할 수 있습니다.
추상 메서드가 추가되면 “규칙과 구현의 강제”까지 확장됩니다.
결국 추상 클래스와 추상 메서드는
“공통성은 유지하면서, 다양성은 보장하는” 객체지향 설계의 핵심 축을 이룹니다.
'구름 > 얄코 Java' 카테고리의 다른 글
| 자바 익명 클래스(Anonymous Class) (0) | 2025.11.02 |
|---|---|
| Java 람다식(Lambda Expression) 완벽 정리 (0) | 2025.11.01 |
| Java 내부 클래스(Inner Class) (0) | 2025.11.01 |
| Java 싱글톤 패턴 (0) | 2025.11.01 |
| Java의 인터페이스란? (0) | 2025.11.01 |
- Total
- Today
- Yesterday
- 그리디알고리즘
- 프로그래머스
- 문자열처리
- 브루트포스
- 그래프 탐색
- 동적계획법
- dfs
- 문제 풀이
- 객체지향
- 알고리즘
- 상속
- c언어
- 동적 계획법
- 그리디
- 알고리즘기초
- DP
- 백준
- 프로그래밍
- python 알고리즘
- 코딩
- 코딩테스트
- 알고리즘 문제풀이
- 문제풀이
- 알고리즘문제풀이
- HTML
- 코딩 테스트
- 파이썬
- C++
- 파이썬코딩
- Python
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 |
