추상클래스 vs 인터페이스

winA·2025년 4월 29일

BE/Java

목록 보기
1/16
post-thumbnail

🥊 사용 목적

  • 추상 클래스: 공통적인 속성과 동작을 가진 객체들의 일반화이다.
  • 인터페이스: 규격만 정의해서 다양한 객체들이 표준화된 사용 방법을 따르게 한다.

🥊 상속

  • 추상 클래스: 단일 상속만 가능하다.
  • 인터페이스: 다중 구현이 가능하다.

클래스에서 다중 상속이 안 되는 이유

자바는 클래스 간의 다중 상속을 허용하지 않는다.

    A
   / \
  B   C
   \ /
    D

D는 B와 C 둘다 상속받지만, method()라는 메소드가 B와 C에 각각 다르게 정의돼있을 때, D는 어떤 method()를 상속받아야 할지 혼란이 생긴다. 이를 다이아몬드 문제라고 한다.

해결책

인터페이스에는 구현 내용이 없다. 인터페이스에는 method명만 선언하고, 실행문은 존재하지 않는다. 그렇기 때문에 B와 C가 같은 이름의 method()을 가지고 있어도 충돌될 내용이 없기 때문에 문제될 것이 없다.

하나의 클래스는 두개 이상의 인터페이스를 implements를 할 수 있다. 이를 통해 인터페이스로서 타입을 여러개 가질 수 있도록 한다.

public class 구현클래스명 implements 인터페이스A, 인터페이스B{
	//모든 추상 메소드 재정의
}
인터페이스A 변수 = new 구현클래스명();
인터페이스B 변수 = new 구현클래스명();
public interface 자식인터페이스 extends 부모인터페이스1, 부모인터페이스2{}

implements 한 모든 인터페이스의 abstract method를 정의해줘야 한다. A와 B에 동일한 메소드가 있을 때 하나의 메소드명으로만 재정의해주면 된다.

🥊 사용 방법

선언

추상클래스

public abstract class Animal{
	//FIELD
	//CONSTR
	//(abstract) METHOD
}

인터페이스

public interface Sleepable{
	//public static final FIELD
	//abstract METHOD
}

사용

추상클래스

public class Bear extends Animal{
	//생성자
	@Override
	//구현메소드
}

인터페이스

public class Bear implements Sleepable{
	@Override
	//구현메소드
}

동시 사용

클래스 상속과 인터페이스 구현을 동시에 선언할 수 있다.

public class D extends C implements A,B{}

🥊 사용처

  • 추상클래스: 여러 클래스에 공통된 속성이다. 기능이 있을 때 기본적인 필드/메소드를 공유하면서 일부만 재정의하고 싶을 때 사용한다.
  • 인터페이스: 어떤 기능을 할 수 있다를 명시하고, 다양한 객체들이 공통 기능을 보장하게 만들고 싶을 때 사용한다.

🥊 다형성

상속은 코드 재사용, 다형성을 구현하는 장점이 있다. 하지만 클래스에서는 다중 상속을 허용하지 않기 때문에 상속을 구현할 때는 보통 인터페이스를 사용하는 추세이다. 문법 자체는 클래스의 상속과 다른 점이 거의 없지만, 실무에서는 인터페이스를 사용한 다형성을 더 많이 사용한다. 인터페이스를 사용하면 객체 간 결합도를 낮출 수 있고, 구현체를 쉽게 교체할 수 있는 유연한 설계가 가능해진다.

객체 간 결합도

💡

자료 결합도: 메소드가 필요한 데이터만 주고받는 방식

구분클래스인터페이스
연결 방식구체적인 구현 클래스에 의존추상적인 기능에만 의존
변경 유연성구현 클래스 변경 시 의존 코드 영향 받음구현체가 바뀌어도 의존 코드 영향 없음
결합도 측면상대적으로 높음훨씬 낮음

인터페이스를 사용하면 약속된 기능(메소드 시그니처)만 의존하고, 구현체가 무엇이든 상관하지 않기 때문에 결합도를 낮출 수 있다. 결합도가 낮아야 유지보수 측면에서 좋은 소프트웨어를 가지고 있다고 한다.

예시

List<String> list = new ArrayList<>();

List는 인터페이스이고, ArrayList는 그 구현체이다. List 타입으로 선언하고, ArrayList 객체를 참조하면, 나중에 다른 구현체로 바로 교체해줄 수 있다.

list = new LinkedList<>();

위와 같이 list에 LinkedList를 대입해도 프로그램 전체 코드를 수정할 필요 없이 List 인터페이스의 모든 메소드를 사용하면 된다.

List라는 하나의 타입만 바라보고, 실제 어떤 구현 객체인지는 나중에 선택/변경이 가능하다.

0개의 댓글