[Java] 자바 추상 클래스(Abstract Class) 사용법 & 예제

추상 클래스(Abstract Class)란?

추상(abstract)이란 무엇일까요? 추상의 사전적 의미는 사물이나 표상(表象)을 어떤 성질·공통성·본질에 착안하여 그것을 추출(抽出)하여 파악하는 것이라고 합니다. 프로그래밍적으로 본다면 객체 간의 공통적 특성을 추출한 클래스라고 생각하시면 되겠습니다. 예를 들자면 강아지, 고양이, 염소라는 객체가 있다고 해봅시다. 이 3가지 객체의 공통점은 동물이라는 공통점이 있습니다. 여기서 동물은 구체적인 실체라기보다는 "수명", "짖기"와 같은 필드와 메서드를 가지고 있는 모든 동물 객체들의 공통되는 특성을 갖고 있는 추상적인 클래스입니다. 

 

 

❓ 추상 클래스는 추상 메서드를 무조건 하나 이상 가져야 할까요?
❌ NOPE!!
👌 추상 클래스는 추상 메소드를 가지지 않아도 상관이 없어요.
👌 하지만, 추상 메소드를 하나라도 가지는 클래스는 반드시 추상 클래스가 되어야 한답니다.

 

 추상클래스 사용 이유 

우리는 추상클래스를 왜 사용해야 할까요? 그 이유는 객체 간의 필드와 메서드의 이름을 통일하여 소스의 가독성을 높이기 위함입니다. 추상 클래스는 상속을 강제합니다. 즉 부모 클래스에는 메서드의 시그니처만 정의해놓고 그 메서드의 실제 동작은 메서드를 상속받은 하위 클래스의 책임으로 위임하고 있습니다.

 

객체들의 필드와 메소드의 이름을 통일하여 소스의 가독성을 높이기 위해서

변수, 메소드은 네이밍이 소스 가독성에 큰 영향을 줍니다. 명칭만으로도 용도를 추측할 수 있기 때문입니다. 이러한 변수와 메서드의 명칭은 각각의 클래스마다 최대한 통일을 시켜줘야 합니다. 그래야 "여기에도 이것이 있겠지" 하고 개발자가 원하는 부분을 방대한 소스 속에서 빠르게 찾아갈 수 있습니다. 예를 들어 동물이라는 추상 클래스에 "짖다"라는 메서드명이 각자 다르다고 생각해봅시다. 개 클래스에는 Bark(),  사자 클래스에는 Roar() 그리고 늑대 클래스에는 Howl()이라는 메서드명으로 각각 지정하였다고 합시다. 언뜻 보면 합리적인 선택으로 보입니다. 영어로 개는 짖을 때 Bark, 사자는 포효할 때 Roar, 늑대는 울 때 Howl이라고 하기 때문입니다. 하지만 이렇게 동일한 기능을 하는 메서드들을 다른 명칭들로 계속해서 작성하다 보면 소스의 가독성이 떨어집니다. 갈수록 코드가 중구난방이 되어버리겠죠. 그래서 장기적인 관점에서 동물이라는 추상 클래스에 Bark()라는 클래스명을 작성하고 그 추상 클래스의 Bark를 아래 객체들이 상속받는 형태로 네이밍을 통일하는 것이 좋습니다.

 

개발의 효율성을 증대시키기 위해서

추상클래스추상 클래스 또한 객체이기 때문에 클래스를 상속하면서 누릴 수 있는 이점들을 추상 클래스도 그대로 누릴 수 있습니다. 예를 들어 많은 객체들을 생성할 때 모든 객체들에 공통적인 메서드와, 필드들을 추상 클래스로 만들고 이 추상 클래스를 하위 자식들이 상속받아 필요한 필드와 메서드를 그대로 상속하고 추상 클래스는 자식에서 재정의하는 방식을 통해 개발의 효율성을 증대시킬 수 있습니다.

 

 자바 추상 클래스 사용법 

자바에서 추상클래스를 선언할 때는 클래스 선언 시 abstract라는 키워드를 붙여서 만들면 됩니다. 단 이렇게 abstract라는 키워드를 붙여 추상 클래스로 만들게 되면 new 연산자를 사용하여 직접 객체를 만들지는 못하고 오직 상속을 통해 자식 클래스만 만드는 용도로만 사용이 가능합니다. 그리고 추상 클래스 내에 추상 메서드라는 메서드를 생성하실 수 있습니다. 이 메서드는 추상 클래스에서 껍데기만 생성하고 상속하는 자식 클래스에서 필수로 오버 라이딩하여 사용합니다.

 

  • 추상 클래스는 인스턴스, 즉 객체를 만들 수 없다. 즉, new를 사용할 수 없다.
  • 추상 메서드는 하위 클래스에게 메서드의 구현을 강제한다. (오버 라이딩이 강제된다.)
  • 추상 메서드를 포함하는 클래스는 반드시 추상 클래스여야 한다.

 

추상 클래스 사용 예제

package Example;

public abstract class Animal {
    String name;
    int age;
    
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void move() {System.out.println("이동한다");}
    public void eat() {System.out.println("먹는다");}
    public abstract void bark(); //짖는 소리는 동물마다 다르므로 추상메서드로 생성
}

추상 클래스도 일반 클래스와 마찬가지로 필드, 생성자, 메서드를 선언하실 수 있으며 자식 객체가 생성될 때 super를 호출하므로 생성자는 반드시 있어야 합니다.  그리고 추상 클래스를 작성하다 보면 선언만 하고 상속받는 자식 클래스에서 메서드를 재정의하여 사용하여야 하는 경우들이 있습니다. 예를 들자면 Animal 클래스의 bark() 메서드죠. 동물마다 짖는 소리는 모두 다르니까요. 이런 경우에는 추상 메서드로 생성을 하면 좋습니다. 추상 메서드는 자식 클래스에서 오버라이드를 강제할 수 있기 때문입니다.

 

package Example;

public class Dog extends Animal{

    public Dog(String name, int age) {
        super(name, age);
    }
    
    @Override
    public void bark() { //메서드 오버라이딩
        System.out.println("멍멍!!");
    }; 
}

개 클래스를 생성합니다. 여기서 bark는 추상메서드로 생성이 되어 있기 때문에 이곳에서 재정의해줍니다.

 

package Example;

public class Cat extends Animal{
    public Cat(String name, int age) {
        super(name, age);
    }
    
    @Override
    public void bark() { //메서드 오버라이딩
        System.out.println("야옹~~");
    }; 
}

고양이 클래스를 생성합니다. 마찬가지로 추상메서드 bark를 이곳에서 오버라이드 합니다.

 

package Example;

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("강아지",3);
        Cat cat = new Cat("고양이",3);
        
        dog.move();
        dog.bark();
        
        cat.move();
        cat.bark();
    }
}

 

댓글

Designed by JB FACTORY