[JAVA] 추상 클래스

용용학생·2024년 4월 23일

자바

목록 보기
20/32

추상 클래스

클래스를 객체를 만들기 위한 설계도로 표현한다면,
추상 클래스는 미완성 설계도로 표현할 수 있다.

클래스가 미완성이라는 뜻은 메소드가 구현이 완료되지 않은, 추상 메소드를 포함하고 있다는 의미이다.

추상 클래스 자체로는 클래스로서의 역할은 못하지만, 새로운 클래스를 작성하는데 있어 바탕이 되는 조상 클래스로서 중요한 역할을 한다.

추상 클래스 & 추상 메소드 형태

추상 클래스

추상 클래스는 abstract 키워드를 붙이기만 하면 된다.

abstract class A { }

abstract 라는 키워드를 보고 이 클래스에는 추상 메소드가 있으니 상속을 통해 구현을 해주어야 한다는 것을 알 수 있다.

추상메소드가 있을 수 있다는 점을 제외하고는 일반 클래스와 동일하다.

추상 메소드

메소드는 선언부와 구현부로 구성되어 있다.
추상 메소드선언부만 작성하고 구현부는 작성하지 않은 채로 남겨둔 것이다.

// 주석을 통해 어떤 기능을 수행할지 설명한다.
abstract 리턴타입 메소드이름();

추상 메소드 역시 앞에 abstract 키워드를 붙여주고
구현부는 만들지 않기 때문에 괄호{ } 대신 세미콜론; 을 붙여준다.


abstract class Pet {
	int color;
    int age;
    
	abstract public void bark();
    
    public void run() {
    	System.out.println("run run");
    }
}

class Dog extends Pet {
	public void bark() {
    	System.out.println("Woof Woof");
    }
}

class Cat extends Pet {
	public void bark() {
    	System.out.println("Meow Meow");
    }
}

추상 클래스는 일반 클래스와 같이 인스턴스 필드도 가질 수 있고 생성자도 가질 수 있다.
다만 미완성 설계도이다보니 인스턴스는 생성하지 못한다

추상 클래스를 상속했지만 추상 메소드를 구현하지 않는다면
그 클래스도 추상 클래스로 선언해야 한다.

근데... 왜 쓸까?

공통 멤버를 통합하여 중복 제거하기

class Marine {
	int x, y;
    void move(int x, int y) { // 지정된 위치로 이동 }
    void stop() { // 현재 위치에 정지 }
    void stimPack() { // 고유 능력, 스팀팩 사용 }
}

class Tank {
    int x, y;
    void move(int x, int y) { // 지정된 위치로 이동 }
    void stop() { // 현재 위치에 정지 }
    void siegeMode() { // 고유 능력 시즈 모드 사용 }
}

class DropShip {
    int x, y;
    void move(int x, int y) { // 지정된 위치로 이동 }
    void stop() { // 현재 위치에 정지 }
    void loadUnload() { // 고유 능력 탑승 사용 }
}

위의 코드처럼 3가지 게임 유닛에 대한 클래스를 작성하고 보니
클래스의 멤버들이 겹치는 것들이 보였다.

이 중복되는 멤버들을 상위 클래스에 묶어놓고 상속을 통해 이용하게 하면 코드의 중복을 제거할 수 있고, 재사용성이 늘어난다.

abstract class Unit {
    int x, y;
    abstract void move(int x, int y); // 지정된 위치로 이동
    void stop() { // 현재 위치에 정지 }
}

class Marine extends Unit{
    void move(int x, int y) {
        // 지정된 위치로 걸어가는 기능 구현
    }
    void stimPack() { // 고유 능력 스팀팩 사용 }
}

class Tank extends Unit{
    void move(int x, int y) {
        // 지정된 위치로 굴러가는 기능 구현
    }
    void siegeMode() { // 고유 능력 시즈 모드 사용 }
}

class DropShip extends Unit{
    void move(int x, int y) {
        // 지정된 위치로 날아가는 기능 구현
    }
    void loadUnload() { // 고유 능력 탑승 사용 }
}

근데 보다보니 굳이 추상 클래스를 쓰지 않고 일반 클래스를 써도 되지 않을까?

class Unit {
	int x, y;
	void move(int x, int y) { }
    void stop() { }
}

저 코드로만으로는 전혀 문제가 생기지 않는다.
그러나 코드를 추가하는 과정 혹은 수정하는 과정에서 문제가 발생할 수 있다.

추상 클래스로 구현 강제하기

만약 게임이 업데이트가 되면서 배틀크루저라는 새로운 유닛이 추가되었다고 가정해보자

class BattleCruiser extends Unit {
	void yamato() { //고유 능력 야마토 스킬 사용 }
}

개발자가 급하게 만드는 바람에 move에 대한 메소드를 오버라이딩하지 않게 되면 큰 문제가 발생한다.
이미 Unit 클래스에는 move 메소드가 구현되어있다 (비록 빈 구현부이지만)
그렇기 때문에 부모 클래스의 메소드가 실행되면서 어떠한 에러도 발생하지 않을 것이다.

일반 클래스를 조상 클래스로 사용하게 되면 이러한 점에서 치명적인 문제가 생길 수 있기 때문에 구현을 강제하는 추상 클래스를 통해 상속 관계를 맺는다면 안정적이고 구조적으로 프로그래밍을 할 수 있다.

profile
자바 스프링 공부하는 정리 블로그!

0개의 댓글