추상 클래스(abstract class)와 인터페이스(interface) 비교

Java에서 추상 클래스와 인터페이스를 헷갈려할 수 있고, 차이점에 대해서 잘 모를 수가 있다.
그 이유는 겉으로 보기에는 똑같아 보이기 때문이다. 하지만 엄연히 다른 목적을 가지고 있다.

인터페이스

인터페이스는 쉽게 말하면 설계도, 명세라고 생각할 수 있다. 인터페이스 안에는 구현된 메소드는 존재하지 않고, 모든 메소드가 추상 함수이고, 일반 변수를 가질 수 없다.
그래서 인터페이스를 상속받은 클래스는 상속받은 메소드들을 모두 구현해야 한다.

인터페이스를 사용하는 이유?

인터페이스를 상속 받고 상속받은 메소드들을 다시 구현해야 한다. 그렇다면 왜 인터페이스라는 것을 만들어서 상속받고 다시 구현하는 귀찮은 짓을 하냐 라고 생각할 수 있다. 인터페이스의 역할을 간단히 말하자면 ‘설계도’라고 말할수 있다. 이러한 설계도를 사용하는 이유는 아래와 같다.

공동 작업시 충돌을 방지하기 위해

예를 들어서 한 팀에서 이동이라는 기능을 개발한다고 했을 때,

class Car{
    public void move(){
          System.out.println("앞으로 이동");
    }
}
// 다른 팀원
class Bicycle{
  public String moving(){
      return "앞으로 이동";
  }
}

이동이라는 기능 개발할 때 각각이 개발한 함수는 각자의 환경에서는 잘 기능하지만, 메인에서 불러와서 사용하기에는 이름도 다르고 반환형도 다르고 하기 때문에 사용하기 불편하다. 유지보수도 힘들어진다. 그런데 인터페이스를 사용하면

interface Transport{
  public void move();
}

class Car implements Transport {
  @Override
  public void move(){
    System.out.println("앞으로 이동");
  }
}


class Bicycle implements Transport {
  @Override
  public void move(){
    System.out.println("앞으로 이동");
  }
}

이제는 메인에서 사용할때 클래스 이름만 알면된다. 인터페이스에서 설계를 해놨기 때문에 무엇을 반환하는지 함수명이 무엇인지 알 수 있기 때문이다.
이러한 장점 때문에 인터페이스를 사용한다.

추상 클래스

일반적으로 java에서 클래스는 일반 클래스와 추상 클래스로 구분되어진다.

추상 클래스는 0개 이상(추상 함수가 없어도 된다) 추상 메소드를 가지고, 일반 메소드, 일반 변수 또한 가질 수 있다.
그래서 인터페이스 역할도 할 수 있고, 구현체도 가지고 있는 돌연변이 같은 클래스이다. 선언은 abstract 키워드를 사용한다.

abstract class Person{
  abstract void eat();

  void eat() {
    ...
  }
}

추상 클래스를 사용하는 이유?

상속을 강제하기 위함이다.
부모 클래스에서 정의만 해놓고, 실제 동작은 자식 클래스에서 하게 된다. 이러한 추상 클래스의 성격이 잘 반영되어진 것이 팩토리 메소드 패턴 (Factory Method Pattern) 이다.

추상 클래스와 인터페이스

왜 둘 사이를 헷갈리고 혼란을 초래하는 것인가?

추상 클래스, 인터페이스 모두 인스턴스화가 될 수 없다. 그래서 겉만 보기에는 인터페이스와 동일하게 보일 수 있다.

인터페이스와 추상 클래스의 사용

인터페이스를 상속하기 위해서는 implements 키워드를 사용하고,
추상 클래스를 상속하기 위해서는 extends 키워드를 사용한다.

class Car implements Vehicle {
  Car() {}
  void run() {
    ....
    }
  void move() {
    ....
    }
}

class Dog extends Animal {
  Dog() {}

  void bark() {
    ....
    }
}

위에 코드를 보면 두 상속 키워드의 차이를 알 수 있을 것이다.
인터페이스 상속 키워드인 implements는 상속받는 모든 메소드를 구현해야한다.
반면 추상 클래스 상속 키워드인 extends는 일반 메소드가 아닌 추상 메소드만 구현했다.

이는 추상 클래스는 키워드 그대로 확장, 상속을 의미한다. 물려준다는 개념이다. 즉, 메소드는 물려받았음으로 구현할 필요가 없다. 그렇기에 부모 - 자식 관계인 계층 구조를 나타낸다.

하지만 인터페이스는 상속 개념이 아닌, 동일한 동작을 위한 구현을 강제화 한다.
결론적으로, 추상 클래스는 상속 개념, 인터페이스는 그렇지 않다는 것을 이해하면 서로 가지는 목적을 구분지을 수 있을 것이다.

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

인터페이스는 추상 클래스보다 추상화 정도가 높은 상태를 정의할 때 사용한다.
인터페이스는 기능의 재정의에 큰 의미를 두고 있다.
멤버 변수와 일반 메소드를 가질 수 없으며 오직 상수와 추상 메소드만을 선언할 수 있다.
implements 키워드를 이용하여 상속을 진행하며 자식 클래스에서 반드시 메소드를 재정의해야합니다.
그리고 인터페이스는 클래스에서 지원하지 않는 다중 상속이 가능하다.

추상 클래스는 abstract을 이용한 미완성 함수로 형태만 정의해두고 몸체는 없는 상태의 클래스를 말한다.
추상 클래스는 상속을 진행하고 상속받는 자식클래스에서 반드시 재정의를 해야한다.
그렇지 않으면 컴파일 에러가 발생한다.
추상클래스는 상속을 통해 기능을 확장하는데에 의미가 있다.
인터페이스는 추상클래스보다 추상화 정도가 높은 상태를 정의할때 사용한다.

예를들면 사람, 원숭이, 닭이라는 클래스가 있을때 숨을 쉰다, 이동한다, 먹는다 이런 개념은 추상클래스로 표현을 할 수 있다.

그렇지만 새라는 클래스가 있을때 ‘난다’라는 메소드를 가지지만 새의 종류가 다 틀려 자식 메소드에서 어짜피 구현해야될 부분이므로 부모 클래스에서 굳이 그 내용을 구현할 필요가 없다.
이럴때 추상메소드 대신 인터페이스를 사용하게 된다.

참고 사이트