프로그래밍 언어/[JAVA]

[JAVA] 추상클래스와 인터페이스의 차이

연구소장 J 2023. 1. 12. 23:41

추상클래스(Abstract Class)란?

추상 클래스(Abstract Class)는 추상 메서드를 선언해 놓고 상속을 통해 자식 클래스에서 메서드를 완성하도록 유도하는 클래스이다. 이러한 특성 탓에 미완성 설계도라고 표현하기도 한다. 추상클래스는 상속을 위한 클래스이기 때문에 따로 인스턴스를 생성할 수 없다.

 

abstract class 클래스{
	...
    public abstract void 메서드();
    
}

class 앞에 "abstract" 예약어를 붙여 해당 클래스가 추상 클래스임을 나타낸다.

또한 메서드도 abstract 예약어를 붙여 추상 메서드를 선언할 수 있다.

 

추상 클래스는 추상 메서드를 가지지 않아도 괜찮다. 다만, 추상 메서드를 하나라도 가진다면 그 클래스는 추상 클래스가 된다.

 

추상 메서드를 선언했다면 자식 클래스는 해당 메서드를 반드시 구현하도록 강제된다.

 

또한 JAVA는 다중 상속을 지원하지 않기 때문에 여러 개의 추상 클래스를 상속할 수 없다.

 

추상 클래스는 static이나 final이 아닌 필드를 가질 수 있다.

 

 

abstract class 클래스{
	...
    public abstract void 메서드();
    
}

class 자식클래스 extends 클래스{
	
    @Override
    public void 메서드(){
    	... // 구현
    }
    
}

 

추상 클래스는 extends 키워드를 통해 상속이 가능하다.

 

 

인터페이스(Interface)란?

인터페이스도 추상 클래스와 비슷하게 다른 클래스를 작성하는데 도움을 주는 목적으로 작성한다.

다만 인터페이스는 추상 클래스보다 추상화 정도가 높아 추상 클래스와 다르게 구현부가 있는 일반 메서드, 일반 변수 멤버 등을 가질 수 없다. 즉, 인터페이스는 구현된 게 아무것도 없는 기본 설계도라고 할 수 있다. 인터페이스 또한 인스턴스를 생성할 수 없다.

 

interface 인터페이스{
    public static final 상수 = 값;
    public abstract void 메서드();
}

 

인터페이스의 모든 멤버 변수는 public static final, 즉 상수이다. public static final은 자동으로 컴파일 시 생성되므로 생략가능 하다.

 

인터페이스의 모든 메서드는 public abstract, 즉 추상 메서드이다. 마찬가지로 public abstract는 생략 가능하다.

 

다만, Java 8에서부터는 다음과 같이 디폴트 메서드와 정적 메서드를 사용할 수 있다.

 

디폴트 메서드 :

public interface Default{     
        // 디폴트 메소드 : 실행 내용까지 작성 가능
        public default void 메서드(){
   
            ... // 구현 내용
            
        }
}

정적 메서드 :

public interface Static{   
        // 정적 메소드
        public static void 메서드(){
            ... // Static.메서드() 와 같이 호출 가능
        }
 }

 

 

또한 인터페이스는 다중상속(구현)이 가능하다.

 

 

추상클래스와 인터페이스의 차이

  추상클래스 인터페이스
다중상속 불가능 가능
추상 메서드 0개 이상 전부
일반 메서드 가능 불가능. 다만 Java8부터는 디폴트, 정적 메서드 구현 가능
필드 일반 변수, 상수 모두 가능 상수(static final)만 가능
상속 키워드 extends implements
접근 제어자 제한 없음 public
공통점
1. 인스턴스를 생성할 수 없다.
2. 상속받은 클래스는 반드시 추상 메서드를 구현해야 한다.

 

추상클래스와 인터페이스의 개념적인 차이는 위 표와 같다. 하지만 기능적으로 봤을 때 둘 다 추상 메서드를 사용해 상속(구현) 받는 클래스가 추상 메서드를 구현하도록 강제하는 점이 같다. 또한, 추상클래스를 보면 다중 상속이 안된다는 점을 제외하고는 인터페이스의 역할을 충분히 할 수 있는 것처럼 보인다.

 

단순히 자바에서 추상 클래스의 다중 상속이 안되기 때문에 인터페이스를 도입한 걸까?

 

둘의 가장 큰 차이는 부모 클래스(인터페이스)와 자식 클래스의 관계이다.

 

  • 추상 클래스 : 자식 클래스 is kind of 부모 클래스 
  • 인터페이스 : 자식 클래스 is able to 부모 인터페이스 

이 관계를 제대로 이해한다면 추상 클래스와 인터페이스의 차이를 이해할 수 있다.

 

이러한 관계를 중점적으로 추상 클래스와 인터페이스를 사용하는 예시를 살펴보자.

 

추상 클래스의 사용

명확한 계층 구조 추상화

추상 클래스 상속 관계
[그림 1] 상속 관계

 

예를 들어 [그림 1]과 같은 상속관계의 클래스들이 있다고 하자.

 

  • 사람 is kind of 포유류
  • 포유류 is kind of 생물체
  • 조류 is kind of 생물체
  • ...

이와 같이 추상 클래스를 상속받는 자식 클래스는 is kind of 관계가 성립한다. 

추상 클래스는 extends 키워드를 사용하는데, 이는 마치 자신의 기능들을 하위 클래스로 확장시키는 느낌이다.

 

이처럼 클래스끼리의 명확한 계층 구조가 필요할 때 추상클래스를 사용할 수 있다. 

예를 들어 삼각형, 네모, 원은 도형이라는 계층 관계로 묶을 수 있다.

 

추상 클래스는 이를 상속받을 각 객체들의 공통점을 찾아 추상화시켜 놓은 것으로, 상속 관계를 타고 올라갔을 때 같은 부모 클래스를 상속하며 부모 클래스가 가진 기능들을 구현해야 할 경우 사용한다.

 

중복 멤버 통합

자식 클래스는 부모 클래스의 일반 멤버 변수도 상속받아 사용할 수 있다. 

예를 들어 [그림 1]에서 모든 생물체가 나이(int age)를 멤버 변수로 가진다고 하자.

만약 추상 클래스를 사용하지 않고 각각 따로 int age 멤버 변수를 가진다면 아래와 같이 정의될 것이다.

public class 포유류{
	int age;
    
    ... // 여러 메서드
}

public class 조류{
	int age;
    
    ... // 여러 메서드
}

 

반면 추상 클래스에 int age를 선언해 놓고 이를 상속받는다면, 중복되는 멤버 변수를 중복으로 선언하지 않아도 된다.

 

public abstract class 생물체{
	int age;
    ... // 여러 메서드
}

public class 포유류 extends 생물체 {
    ... // 여러 메서드
}

public class 조류  extends 생물체 {    
    ... // 여러 메서드
}

이처럼 자식 클래스 is kind of 부모 클래스의 관계가 성립하기 때문에 일반 멤버 변수의 통합도 가능하다.

 

추상 클래스를 이용하면 중복 멤버 변수의 통합이 가능하다. 인터페이스는 일반 멤버 변수를 선언하지 못하고 상수만 선언할 수 있기 때문에 이러한 중복 멤버 변수의 통합이 불가능하다. static final 상수를 선언한다면 각 클래스에서 값의 변경이 불가능할 것이다.

 

인터페이스의 사용

자유로운 관계 묶음

[그림 1]에서 박쥐와 독수리는 날 수 있고, 사람과 펭귄은 수영할 수 있다고 하자.

 

이때 박쥐와 독수리의 기능에 fly() 메서드를 추가하고 싶다면, 부모 클래스인 포유류나 조류에 fly() 메서드를 선언할 수 없다. 사람이나 펭귄은 날 수 없는데 메서드의 구현을 강제받기 때문이다.

 

어쩔 수 없이 박쥐와 독수리는 따로 fly() 메서드를 각자 구현해야 한다. 공통된 기능이 있음에도 추상화할 수 없는 것이다.

 

하지만 이때 인터페이스를 도입한다면 공통된 기능을 뽑아낼 수 있다.

 

인터페이스
[그림 2] 인터페이스

 

  • 박쥐 is able to 날기
  • 독수리 is able to 날기
  • 사람 is able to 수영
  • 펭귄 is able to 수영

위와 같이 is able to 관계에서는 인터페이스를 사용할 수 있다. 인터페이스는 추상 클래스보다 상대적으로 자유로운 관계 묶음이 가능하다. 서로 관련성이 없는 클래스들이더라도 같은 동작을 한다면 하나의 인터페이스로 묶을 수 있다. 심지어 다중 상속도 가능하기 때문에 다양한 인터페이스를 implements(구현)해서 기능을 구현할 수 있다.

 

인터페이스는 상속 관계를 타고 올라갔을 때 다른 조상 클래스를 상속하더라도, 같은 기능이 필요할 경우 사용한다. 클래스와 별도로 구현 객체가 같은 동작을 한다는 것을 보장하기 위해 사용한다.

 

이처럼 자유로운 관계 묶음이 필요할 때 인터페이스를 사용할 수 있다. 

 

특히, is able to 관계에 있을 때 인터페이스를 사용할 수 있다. 이러한 이유 때문인지 인터페이스명은 ~able로 끝나는 경우가 많다. 어떤 기능 또는 행위를 하는데 필요한 메서드를 제공한다는 의미를 강조하기 위해서다.

ex) Comparable, Serializable... 등

 

 

다중 상속이 필요한 경우

[그림 2]에서 사람은 말을 할 수 있다는 기능인 speak()를 추가한다고 하자. 이 또한 나중에 말을 할 수 있는 생물체가 나타날 수도 있으므로(물론 가능성이 낮지만) 추상화시켜 본다고 하자.

 

인터페이스 다중 상속
[그림 3] 인터페이스 다중 상속

 

인터페이스는 다중 상속(구현)이 가능하기 때문에 "사람 implements 말할 수 있는"이 가능하다.

 

 

정리

정리하자면 추상 클래스는 is kind of 관계로 관련성이 높은 명확한 계층 구조의 추상화에 사용되며, 인터페이스는 is able to 관계로 관련성이 낮더라도 기능에 따른 추상화가 필요하거나 다중 상속(구현)이 필요할 때 사용된다

 

 

 

 


참고

 

1. https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-vs-%EC%B6%94%EC%83%81%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0#thankYou

2. https://velog.io/@new_wisdom/Java-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-%EC%B0%A8%EC%9D%B4

3. https://devlog-wjdrbs96.tistory.com/370

 

반응형