-
[Java] Abstract Class(추상 클래스)와 Interface(인터페이스)의 차이Programming/Java 2021. 8. 15. 16:55
객체지향에 있어서 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'Programming > Java' 카테고리의 다른 글
[Java] Hotspot JVM Garbage Collection 과정 (406) 2021.08.23 [Java] Primitive Data Types (336) 2021.08.22 [Java] String 🆚 StringBuffer 🆚 StringBuilder 무슨 차이일까? (0) 2021.07.23 [Java] Java API HashMap은 어떻게 동작할까 (0) 2021.06.20 [Java] Primitive Wrapper Class (0) 2021.04.13