자바(JAVA) 기초 함께 알아보자

자바(JAVA) 기초 함께 알아보자(26) - 추상 클래스/추상 메소드 (abstract)

jay_the_code 2025. 2. 11. 15:00

지난번 다중 상속 / 인터페이스 (Interface)에 이어서

이번글에서는 추상 클래스와 추상 메소드(abstract)

에 대해서 알아보겠습니다.

 

추상 클래스 그리고 추상 메소드에 대해서

이해하기 위해서는 이러한 개념들이

등장한 이유에 대해서 생각해봐야 합니다.

추상 클래스 (abstract class) / 추상 메소드(abstract method)

 

지금부터 하려는 이야기를 이해하기

위해서는 상속(Inheritance)에 대한 이해가

필수적이므로 혹시 상속에 대해서

잘 모르시는 분들은 아래 링크 참고 부탁드립니다.

https://jaythecode.tistory.com/19

 

자바(JAVA) 기초 함께 알아보자(19) - 상속(Inheritance)

지난번 HashMap에 이어서 이번글에서상속(Inheritance)에 대해서 알아보겠습니다.상속은 객체지향(object-oriented) 언어에서 가장 중요하고많이 쓰이는 개념입니다.먼저 그럼 상속이 일어나는 상황을 한

jaythecode.tistory.com

 

상속을 하게 되면 부모 클래스

그리고 자식 클래스 두 가지 클래스가

생기게 되는데 이때 한 가지 문제

발생할 수 있습니다.

 

만약 부모 클래스로 인스턴스를

생성하면 안 되는 경우가 있다면

어떨까요?

 

쉽게 게임으로 예를 들어 보겠습니다.

 

먼저 캐릭터 중에 궁수가 있다고 생각해 봅시다.

A 궁수 캐릭터는 명중률이 5이고

활을 15개까지 가지고 다닐 수 있습니다.

 

반면에 B 궁수 캐릭터는 명중률이 10이고

활을 8개까지 가지고 다닐 수 있습니다.

 

A와 B 캐릭터는 모두 궁수 클래스를 상속받는

다고 가정했을 때

 

만약 궁수 클래스 자체로 인스턴스가

생성가능하다면 명중률이 10이고 활을 15개인

인스턴스가 생성될 가능성이 존재합니다.

 

이렇게 될 경우에 개발자의 의도와는

다른 프로그램의 인스턴스가 생성될 수 있고

이는 치명적인 오류를 발생시킬 수 있습니다.

 

아래 코드들을 통해 위 이야기를

다시 살펴보겠습니다.

class Archer{
	int accuracy, capacity;
    
    Archer(int accuracy, int capacity){
    	this.accuracy = accuracy;
        this.capacity = capacity;
    }

    public int getAccuracy(){
    	return this.accuracy;
    }
    
    public int getCapacity(){
    	return this.capacity;
    }
}

class Acura extends Archer{
    Acura(){
    	super(5, 15);
    }
    
    @Override
    public int getAccuracy(){
    	return this.accuracy;
    }
    
    @Override
    public int getCapacity(){
    	return this.capacity;
    }
}

class Bruno extends Archer{
	Bruno(){
    	super(10, 8);
    }
    
    @Override
    public int getAccuracy(){
    	return this.accuracy;
    }

    @Override
    public int getCapacity(){
    	return this.capacity;
    }
    
    
}

class Test{

    public static void main(String[] args){

        Archer a = new Archer(10, 15);
        Acura acu = new Acura();
        Bruno bru = new Bruno();

        System.out.println("Archer accuracy, capacity");
        System.out.println(a.getAccuracy());
        System.out.println(a.getCapacity());
        System.out.println("--------------------------");
        System.out.println("Acura accuracy, capacity");
        System.out.println(acu.getAccuracy());
        System.out.println(acu.getCapacity());
        System.out.println("--------------------------");
        System.out.println("Bruno accuracy, capacity");
        System.out.println(bru.getAccuracy());
        System.out.println(bru.getCapacity());
    }
}

 

위 코드를 실행시켜 보시면 실제로 Archer클래스

인스턴스가 생성되었고 이의 accuracycapacity

모두 설정한 대로 10과 15로 나타난 것을 확인할 수

있습니다.

 

그럼 지금부터 이를 방지하기 위해 탄생한

추상 클래스(abstract class)에 대해서

알아보겠습니다.

 

추상 클래스를 만드는 방법은

기존 클래스를 만드는 방법과 동일합니다.

 

' abstract class 클래스명 '과

같은 방식으로 선언하고 안의 내용은

기존 클래스와 동일하게 작성합니다.

 

이때 추상 메소드(abstract method)

개념을 알아두면 함께 사용 가능합니다.

 

기존 상속에서는 부모 클래스의 메소드

전부 상속받아야 하는 의무는 없었습니다.

 

하지만 메소드를 abstract로 선언할 경우

자식 클래스는 부모 클래스의

추상 메소드를 무조건 가지고 있어야 합니다.

 

이때 주의해야 할 점은 추상 메소드를

사용하기 위해서는 추상메소드를 가지고 있는

클래스 또한 추상 클래스이어야 한다는 것입니다.

 

그 이유는 메소드가 추상 메소드일 경우에

구현부를 가지고 있지 않기 때문에

인스턴스화할 수 없고 따라서 자연스럽게

클래스 또한 추상 클래스로 선언함으로써

인스턴스화를 방지합니다.

 

그럼 아래에서 추상 클래스와 추상 메소드를

사용하는 예시를 직접 살펴보겠습니다.

 

// 추상 클래스
abstract class Archer{
	int accuracy, capacity;
    
    Archer(int accuracy, int capacity){
    	this.accuracy = accuracy;
        this.capacity = capacity;
    }

	// 추상 메소드
    abstract int getAccuracy();
    abstract int getCapacity();
}

class Acura extends Archer{
    Acura(){
    	super(5, 15);
    }
    
    @Override
    public int getAccuracy(){
    	return this.accuracy;
    }
    
    @Override
    public int getCapacity(){
    	return this.capacity;
    }
}

class Bruno extends Archer{
	Bruno(){
    	super(10, 8);
    }
    
    @Override
    public int getAccuracy(){
    	return this.accuracy;
    }

    @Override
    public int getCapacity(){
    	return this.capacity;
    }
    
    
}

class Test{

    public static void main(String[] args){

        Archer a = new Archer(10, 15);
        Acura acu = new Acura();
        Bruno bru = new Bruno();

        System.out.println("Archer accuracy, capacity");
        System.out.println(a.getAccuracy());
        System.out.println(a.getCapacity());
        System.out.println("--------------------------");
        System.out.println("Acura accuracy, capacity");
        System.out.println(acu.getAccuracy());
        System.out.println(acu.getCapacity());
        System.out.println("--------------------------");
        System.out.println("Bruno accuracy, capacity");
        System.out.println(bru.getAccuracy());
        System.out.println(bru.getCapacity());
    }
}

 

위 코드를 다시 실행시켜 보면

Archer a = new Archer(10, 15) 부분에

오류가 발생하는 것을 확인할 수 있습니다.

 

또한 추상 메소드는 구현부가 없기 때문에

' abstract 반환값 메소드명(); '과 같은 형태로

작성합니다.

 

지금까지 추상 클래스, 추상 메소드에 대해서

알아보았습니다.

 

추상 클래스와 추상 메소드는 예상치 못하는

치명적인 오류를 방지해 줌과 동시에 하위 클래스들에게

메소드를 강제함에 따라

클래스 설계를 수월하게 해주는 개념들입니다.

 

상속까지의 기본개념들을 충분히 익힌 상태라면

추상 클래스와 추상 메소드의 개념까지 익혀서

한 단계 레벨업 하시기를 바라겠습니다.

 

다음 글에서는 Collections 클래스에 대해서

알아보겠습니다.