728x90
추상 클래스란?
- 08장에서 배운 상속을 기반으로 이 장에서는 추상 클래스에 대해 알아보겠습니다.
- 추상 클래스는 완전하지 않은 클래스입니다.
- 완전하지 않다는 것이 부족하다는 뜻일 수도 있지만, 다른 한편으로는 완성되지 않았기 때문에 가능성이 남아 있다는 의미입니다.
- 이 가능성을 활용해 좀 더 확장 가능하고 다양한 프로그램을 개발할 수 있습니다.
- 추상 클래스에 대해서 배우기 전에, '추상적이다' 라는 말에 대해서 먼저 생각해볼까요?
- 추상적이라는 것은 구체적이지 않고 막연한 것을 뜻합니다.
- '구체적이지 않고 막연한 클래스' 라는 것은 무엇을 의미하는 것일까요?
- 추상 클래스를 영어로 표현하면 abstract class 이고, 추상 클래스가 아닌 클래스는 concrete class 라고 합니다.
- 우리가 지금까지 만든 클래스는 모두 concrete class 였습니다.
- 추상 클래스 문법부터 배워 보겠습니다.
추상 클래스 문법
- 추상 클래스는 항상 추상 메서드를 포함합니다.
- 추상 메서드는 무엇일까요?
- 추상 메서드는 선언부만 가지고 구현부는 가지지 않은 메서드를 의미합니다.
- 중괄호 { } 로 감싼 부분을 함수의 구현부(implementation) 이라고 합니다.
- 이 부분이 없는 함수는 추상 함수(abstract function) 이고 자바에서는 추상 메서드(abstract method) 라고 합니다.
- 추상 메서드는 다음과 같이 선언만 하며 abstract 예약어를 사용합니다. 그리고 { } 대신 ; 를 사용합니다.

- 참고로 int add(int x) {} 는 concrete class 입니다. 구현부에 내용이 없을 뿐 구현부가 있기 때문입니다.
- 정리하자면, 자바에서 추상 메서드는 abstract 예약어를 사용하여 선언만 하는 메서드입니다.
메서드 선언의 의미
- 우리가 코딩을 한다고 하면 뭔가 열심히 구현하는 것을 생각하기 마련입니다.
- 변수를 선언하고 제어문을 사용하여 로직을 만들고 기능을 구현하는 것을 프로그램 개발이라고 생각합니다.
- 하지만 로직을 구현하는 것보다 더 중요한 것이 어떻게 구현할지를 결정하는 것입니다.
- 이런 과정을 개발 설계라고 합니다.
- 설계 과정에는 다양하고 복잡한 방법들이 있습니다.
- 예를 들어 이런 경우를 생각해 보겠습니다.
int add(int num1, int num2);
- 위 코드를 보겠습니다.
- 선언한 메서드를 보면 두 개의 정수를 입력받은 후 더해서 그 결가 값을 반환한다는 것을 유추할 수 있습니다.
- 즉 이 메서드의 선언부(declatration)만 봐도 어떤 일을 하는 메서드인지 알 수 있다는 겁니다.
- 함수의 선언부 즉 반환 값, 함수 이름, 매개변수를 정의한다는 것은 곧 함수의 역할이 무엇인지, 어떻게 구현해야 하는지를 정의한다는 뜻입니다.
- 따라서 함수 몸체를 구현하는 것보다 중요한 것은 함수 선언부를 작성하는 것입니다.
추상 클래스 구현하기
- 구체적으로 구현하지 않은 추상 메서드를 어떻게 사용하는지 하나씩 살펴보겠습니다.

- 위의 클래스 다이어그램을 살펴보겠습니다.
- 클레스 다이어그램 맨 위쪽에는 클래스 이름을 씁니다.
- 그리고 아래쪽에 변수 이름을 쓰고 그 다음에 메서드 이름을 씁니다.
- 추상 클레스와 추상 메서드는 기울임꼴로 표시합니다.
- Computer 클래스는 추상 클래스입니다.
- 이를 상속 받은 두 클래스 중 DeskTop 클래스는 일반 클래스이고 NoteBook 클래스는 추상 클래스입니다.
- NoteBook 클래스를 상속받은 MyNoteBook 클래스는 일반 클래스입니다.
- Computer 클래스가 제공하는 메서드 중 두 개는 기울임꼴 서체로 표시했습니다. 즉 2개는 일반 메서드, 2개는 추상 메서드라는 것을 의미합니다.
- 위 다이어그램을 토대로 프로그램을 구현해봅시다.
public class Computer {
public void display(); // 오류 발생
public void typing();
public void turnOn() {
System.out.println("전원을 켭니다.");
}
public void turnOff() {
System.out.println("전원을 끕니다.");
}
}
- display() 메서드와 typing() 메서드에서 오류가 발생하고 있는 것을 알 수 있습니다.
- 오류를 해결하는 2가지 방법은 자연스럽게 impletation (body) 부분을 작성하거나 이 메서드를 추상 메서드로 바꾸는 것입니다.
- abstract 예약어를 추가하면 추상 메서드를 생성할 수 있습니다.
public class Computer { // 오류 발생
public abstract void display();
public abstract void typing();
public void turnOn() {
System.out.println("전원을 켭니다.");
}
public void turnOff() {
System.out.println("전원을 끕니다.");
}
}
- 하지만 이번에는 메서드와 클래스 이름에 모두 오류가 표시됩니다.
- 왜냐하면 추상 메서드가 속한 클래스를 추상 클래스로 선언하지 않았기 때문입니다.
- 이 오류를 해결하려면 클래스를 abstract 예약어와 함께 추상 클래스로 설정하거나 추상 메서드를 일반 메서드로 만들면 됩니다.
- Computer 클래스를 추상 클래스로 만들면 오류가 해결 됩니다.
public abstract class Computer {
public abstract void display();
public abstract void typing();
public void turnOn() {
System.out.println("전원을 켭니다.");
}
public void turnOff() {
System.out.println("전원을 끕니다.");
}
}
- Computer 클래스를 이와 같이 구현한 것은 'Computer 를 상속받는 클래스 중 turnOn( ) 과 turnOff( ) 구현 코드는 공통이다. 하지만 display( ) 와 typing( ) 은 하위 클래스에 따라 구현이 달라질 수 있다. 그래서 Computer 에서는 구현하지 않고, 이 두 메서드 구현에 대한 책임을 상속받는 클래스에 위임한다'라는 의미입니다.
- 따라서 Computer 클래스의 추상 메서드는 추상 클래스를 상속받은 DeskTop 과 NoteBook 에서 실제로 구현하게 됩니다.
- DeskTop 클래스를 만들어 보겠습니다.
public class DeskTop extends Computer{ // 오류 발생
}
- 상속 받은 DeskTop 클래스에 오류가 발생합니다.
- 오류 메시지를 보면 2가지 오류가 있다고 말해줍니다.
- 구현 되지 않은 메서드가 있습니다 (Add unimplemented methods)
- DeskTop 클래스를 추상 클래스로 만드세요 (Make type 'DeskTop' abstract)
- 원래 Computer 는 추상 클래스입니다.
- 추상 클래스를 상속받은 클래스는 추상 클래스가 가진 메서드를 상속받습니다.
- 따라서 상속받은 클래스는 추상 메서드를 포함합니다.
- 그렇기 때문에 추상 메서드를 모두 구현하여 추상 메서드가 없는 상태로 만들거나, 추상 클래스를 상속받은 하위 클래스도 추상 클래스로 만들어야 합니다.
public class DeskTop extends Computer{
@Override
public void display() {
System.out.println("DeskTop display()");
}
@Override
public void typing() {
System.out.println("DeskTop typing()");
}
}
- 오류 메시지 중 Add unimplemented methods 를 클릭하면 자동으로 구현해야 하는 추상 메서드들이 생겨납니다.
- 그 다음 구성하고 싶은 몸체 코드를 작성하면 됩니다.
- 마찬가지로 NoteBook 클래스도 구현해봅시다.
public abstract class NoteBook extends Computer{
@Override
public void display() {
System.out.println("NoteBook display( )");
}
}
- NoteBook 클래스에서는 상속받은 추상 메서드를 모두 구현하지 않았습니다. (다이어그램에서 설계한 것에 따라)
- 그러므로 NoteBook 클래스는 상위 클래스인 추상 클래스로부터 상속받은 추상 메서드가 하나 남아있습니다.
- 따라서 NoteBook 클래스는 자연스럽게 추상 클래스가 됩니다.
- NoteBook 클래스를 상속받는 MyNoteBook 클래스도 구현해보겠습니다.
public class MyNoteBook extends NoteBook {
@Override
public void typing() {
System.out.println("MyNoteBook typing()");
}
}
- MyNoteBook 클래스는 상속받은 추상 메서드를 모두 구현했으므로 일반 클래스가 됩니다.
모든 추상 메서드를 구현한 클래스에 abstract 예약어를 사용한다면?
public abstract class AbstractTV {
public void turnOn() {
System.out.println("전원을 켭니다.");
}
public void turnOff() {
System.out.println("전원을 끕니다.");
}
}
- 문법상으로 모든 메서드를 구현했어도 abstract 예약어를 사용하면 추상 클래스입니다.
- 이 클래스는 모든 추상 메서드를 구현한 클래스입니다.
- 하지만 이것으로는 완벽한 TV 기능이 구현된 것이 아니고 TV의 공통 기능만을 구현해 놓은 것입니다.
- 이 클래스는 생성해서 사용할 목적이 아닌 상속만을 위해 만든 추상 클래스입니다.
- 이 경우에 new 예약어로 인스턴스를 생성할 수 없습니다.
추상 클래스를 만드는 이유
- 지금까지 추상 클래스를 어떻게 정의하고 구현하는지 이야기했습니다.
- 그렇다면 이런 추상 클래스는 어디에 사용하기 위해 만드는 걸까요?
- 예제를 보면서 얘기하겠습니다.
public class ComputerTest {
public static void main(String[] args) {
Computer c1 = new Computer(); // 오류 발생
Computer c2 = new DeskTop();
Computer c3 = new NoteBook(); // 오류 발생
Computer c4 = new MyNoteBook();
}
}
- Computer 클래스형으로 인스턴스를 4개 생성했습니다.
- 코드를 보면 Computer 와 NoteBook 인스턴스에서 오류가 납니다.
- 오류 메시지를 보면 다음과 같습니다.
Cannot instantiate the type Computer : 해당 클래스를 인스턴스로 생성할 수 없습니다.
추상 클래스는 인스턴스로 생성할 수 없다
- 추상 클래스는 모든 메서드가 구현되지 않았으므로 인스턴스로 생성할 수 없습니다.
- 예를 들어 오른쪽과 같은 ABC 클래스가 있다고 가정해봅시다.
abstract class ABC {
abstract void a();
void b() {
System.out.println("b( )");
}
}
- ABC 클래스는 추상 클래스이며 a( ) 추상 메서드를 가지고 있습니다.
- 만약 ABC 클래스를 생성할 수 있어서
ABC abc = new ABC(); - 위 문장이 가능하다면 abc.a( ) 메서드를 호출했을 때 어떤 코드가 수행될까요?
- 정답은 아무것도 수행되지 않습니다. 구현된 코드가 없으니까 당연하겠죠.
- 따라서 이런 문제를 예방하기 위해 추상 클래스는 인스턴스를 생성할 수 없도록 되어있습니다.
- 다만, 추상 클래스라도 상위 클래스로 묵시적 형 변환은 가능합니다.
추상 클래스에서 구현하는 메서드 (★ 추상 클래스의 사용 목적, 추상 메서드의 사용 목적)
- 생성할 수 없는 추상 클래스는 어디에 쓰는 걸까요?
- 추상 클래스는 상속을 하기 위해 만든 클래스입니다.
- 그렇다면 어떤 메서드를 구현하고, 어떤 메서드를 구현하지 않고 추상 메서드로 남겨두는 걸까요?
- 추상 클래스에서 구현하는 메서드는 하위 클래스에서도 사용할 메서드입니다. 즉 하위 클래스 모두가 사용할 공통 메서드를 의미합니다.
- 반대로 추상 클래스에서 구현하지 않은 추상 메서드는 하위 클래스에서 각자 다른 내용으로 구현해야 하는 메서드를 의미합니다. 이렇게 추상 메서드로 남겨두어 구현 내용을 하위 클래스에서 구현 하도록 위임하는 것을 의미합니다.
- 표로 정리해서 보면 아래와 같습니다.
| 구현된 메서드 | 하위 클래스에서 공통으로 사용할 메서드, 하위 클래스에서 재정의할 수도 있다. |
| 추상 메서드 | 하위 클래스가 어떤 클래스냐에 따라 구현 코드가 달라질 메서드, 하위 클래스에서 구현하도록 위임 되었다. |

추상 클래스와 프레임워크
- 실제로 추상 클래스는 많은 프레임워크에서 사용하고 있는 구현 방식입니다.
- 예를 들어 안드로이드를 생각해 보면, 안드로이드 앱을 만들 때 안드로이드 라이브러리에서 제공하는 많은 클래스를 사용합니다.
- 이들 클래스 중에는 모두 구현된 클래스도 있지만, 일부만 구현되어 있어서 상속을 받아 구현하는 경우도 많습니다.
- 이때 안드로이드에서 구현해 놓은 코드는 내부적으로 사용하거나 상속받은 모든 클래스가 공통으로 사용할 메서드입니다.
- 그리고 구현을 미루어 놓은 메서드(추상 메서드)는 실제로 앱에서 어떻게 만드냐에 따라 다르게 구현해야할 내용으로 앱에서 구현하도록 선언만 해둔 것을 의미합니다.
'[그린컴퓨터] Server > JAVA(객체 지향 프로그래밍)' 카테고리의 다른 글
| 템플릿 메서드 응용하기 { 예제 이해하기, 클래스 기능과 관계, 클래스 설계하기, 추상 클래스와 다형성 } (0) | 2023.06.01 |
|---|---|
| 템플릿 메서드 { 추상 클래스와 템플릿 메서드, 템플릿 메서드의 역할, final } (0) | 2023.06.01 |
| 다운 캐스팅과 instanceof { 다운 캐스팅이란, instanceof란 } (0) | 2023.05.31 |
| 다형성 활용하기 { 배열과 다형성, 배열과 다형성 활용하기, 상속은 언제 사용할까 } (0) | 2023.05.31 |
| 다형성 { 다형성이란, 다형성의 장점 } (0) | 2023.05.31 |