Programming/Java

[Java] Abstract Class(추상 클래스)와 Interface(인터페이스)의 차이

이진2 2021. 8. 15. 16:55

https://pediaa.com/wp-content/uploads/2018/09/Difference-Between-Abstract-Class-and-Interface-in-Java-Comparison-Summary.jpg

객체지향에 있어서 Abstraction(추상화)는 단순한 인터페이스를 통해 구현의 복잡성을 숨기고 기능을 제공할 수 있는 핵심 개념이다.

Java에서 추상화는 주로 Interface(이후 인터페이스)와 Abstract Class(이후 추상클래스)를 통해 구현할 수 있다

 

1. Class와 Interface

Class: 객체를 생성하기 위해 변수와 메소드를 정의하는 사용자 정의 타입. 상태와 행동을 결정하는 property와 method들로 이루어져 있다
Interface: 클래스와 유사하지만 필드 상수와 메소드 정의부를 가지고 있는 사용자 정의 타입. 인터페이스 내의 모든 메소드는 구현체를 포함할 수 없음(Java 8미만. 8 이후 부터는 default와 static 메소드에 한해 구현체를 가질 수 있다)

 

2. Abstract Class 🆚 Interface

  Abstract Class Interface
사용 가능 변수 final, non-final, static, non-static variables static, final
사용 가능 접근 제어자 제한 없음 public
사용 가능 메소드 abstract method, non-abstract method abstract method
상속 키워드 extends implements
다중 상속 가능 여부 불가능 가능 ( ex. A class implements B, C )
사용 키워드 abstract interface
공통점 1. 인스턴스화 할 수 없다
➡ new TypeName()을 사용할 수 없다
➡ 인터페이스 혹은 추상 클래스를 상속받아 구현한 구현체의 인스턴스를 사용한다 (혹은 위와 같은 명령문을 사용할 경우 Anonymous Class를 사용하여 모든 메소드를 재정의 해야 한다)

2. 구현 여부에 관계 없이 선언 및 정의된 메소드 집합을 포함할 수 있다

 

3. Interface를 사용할 때

  • 다중 상속을 사용(Java에서는 기본적으로 다중 상속을 지원X)해야 할 때
  • 관련성이 없는 클래스가 인터페이스를 구현할 때 (ex. compareTo()를 사용하기 위한 Comparable interface 구현)
  • 어플리케이션의 기능을 정의해야 하지만 그 구현 방식이나 대상에 대해 추상화 할 때
  • HAS - A의 관계일 때

 

public interface Sender {
    void send(File fileToBeSent);
}
public class ImageSender implements Sender {
    @Override
    public void send(File fileToBeSent) {
        // image sending implementation code.
    }
}
@Test
void givenImageUploaded_whenButtonClicked_thenSendImage() { 
 
    File imageFile = new File(IMAGE_FILE_PATH);
 
    Sender sender = new ImageSender();
    sender.send(imageFile);
}

위의 예시에서는 "Sender가 파일을 전송할 수 있다"라는 행동을 정의할 때, 인터페이스를 사용했다.

ImageSender 클래스는 Sender 인터페이스를 구현하여 이미지 전송 비즈니스 로직을 구현할 수 있고, VideoSender / DocumentSender와 같이 다양한 작업들이 인터페이스 구현을 통해 만들어질 수 있다.

 

Interface는 부모-자식 관계로 연관된 상속이 아니라 Abstract Method를 정의하고 오버라이딩을 통해 여러 가지 형태로 구현할 수 있는 다형성의 개념에 더 가깝다.

하지만 인터페이스의 특성 상 인터페이스를 구현하는 하위 클래스는 모든 추상 메소드를 구현해야 하는 강제성을 가지기 때문에, 공통된 기능(만약 존재한다면) 또한 일일히 구현해야 하는 번거로움이 생긴다.

 

4. Abstract Class를 사용할 때

  • 하위 클래스가 오버라이드하여 재정의하는 기능들을 공유하기 위한 상속 개념을 사용할 때(많은 연관된 클래스들 간에 코드를 공유)
  • 요구사항과 함께 구현 세부 정보의 일부 기능만 지정했을 때
  • 인스턴스의 상태를 수정하기 위해 non-final / non-static 메소드를 사용해야 할 때
  • IS - A 관계일 때

 

public abstract class Vehicle {
    
    protected abstract void start();
    protected abstract void stop();
    protected abstract void drive();
    protected abstract void changeGear();
    protected abstract void reverse();
    
    // standard getters and setters
}
public class Car extends Vehicle {

    @Override
    protected void start() {
        // code implementation details on starting a car.
    }

    @Override
    protected void stop() {
        // code implementation details on stopping a car.
    }

    @Override
    protected void drive() {
        // code implementation details on start driving a car.
    }

    @Override
    protected void changeGear() {
        // code implementation details on changing the car gear.
    }

    @Override
    protected void reverse() {
        // code implementation details on reverse driving a car.
    }
}
@Test
void givenVehicle_whenNeedToDrive_thenStart() {

    Vehicle car = new Car("BMW");

    car.start();
    car.drive();
    car.changeGear();
    car.stop();
}

Abstract Class는 부모-자식 간의 연관성을 갖는 상속 관계에서 공통된 기능을 구현하고, 확장하는 데에 사용된다.

 

5. Interface 🆚 Abstract Class 예시

이 그림을 보면, Animal과 Fish는 Creature를 상속 받는다. Creature가 가지고 있는 공통 메소드에는 숨쉬기, 먹기 등이 있을 것이다.

하지만 그 구현 방법은 Animal과 Fish가 다르기 때문에(아가미, 폐 호흡) Abstract Method로 정의하여 하위 클래스에게 상속해줄 수 있다.

각각의 클래스에서 Abstract Method를 구체화 해준 뒤 실제 Class가 다시 상속받을 수 있다. Abstract Class는 이와 같이 상속 관계를 표현한다.

 

사람과 호랑이는 뛰는 방식이 이족보행/사족보행으로 다르고, 사람과 고래는 지느러미를 이용한 수영/팔을 이용한 수영 등으로 기능을 구현하는 방식이 모두 다르다.

이처럼 인터페이스는 상속의 개념과 관계 없이 각각의 공통된 특성을 추상화한 뒤 구현하는 클래스에게 제공한다. 

 

 

참고 사이트
- https://www.baeldung.com/java-interface-vs-abstract-class
- https://myjamong.tistory.com/150
- https://velog.io/@gillog/Java-Interface-vs-Abstract-Class-%EC%A0%95%EB%A6%AC