Posts [Java] 추상 메서드 vs 인터페이스 (Abstract Class vs Interface)
Post
Cancel

[Java] 추상 메서드 vs 인터페이스 (Abstract Class vs Interface)

Introduction

비슷한 듯 다른 추상 메서드와 인터페이스.
헷갈리는 두 개념을 제대로 정의해보자.

Abstraction

  • 선언부(어떤 것이 동작하는지)는 보여주고, 내부 구현부(어떻게 동작하는지)는 숨기는 형태.
  • 추상 메서드와 인터페이스 둘 다 추상화를 위해 사용된다.

Abstract Class

  • 추상 메소드(abstract method)가 하나 이상 포함된 경우 or abstract로 정의된 경우

추상 클래스는 추상 메소드를 최소한 하나라도 가져야 할까?
👉 NOPE.
👉 추상 클래스는 추상 메소드를 가지지 않아도 상관없다.
👉 단, 추상 메소드를 하나라도 가지는 클래스는 추상 클래스가 되어야 한다.

  • 필드, 생성자, 추상 메소드를 가질 수 있다.
  • 생성자를 가지기 때문에 객체화가 가능하다.

추상 클래스도 생성자를 가질 수 있을까?
👉 YES.
👉 추상 클래스의 생성자는 일반 클래스에 필요한 어떤 제약을 줄 때 사용한다.
👉 추상 클래스의 생성자는 하위 클래스의 생성자에서 super()를 통해 부르고 초기화 시킨다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public abstract class AbstractClass {

    // Field
    private String name;
    private String id;

    // Constructor 
    public AbstractClass(String name, String id){
      this.name = name;
      this.id = id;
    }

    // Abstract Method
    public method() { }
}

public class RealClass extends AbstractClass {

    private String number;

    public RealClass(String name, String id, String number) {
      super(name, id);
      this.number = number;
   }
}


  • 추상 클래스는 상속(extends)된다.
  • 상속은 is a kind of(~의 한 종류)라는 의미를 가진다.

👉 ex. 뽀로로 is a kind of 펭귄 == 뽀로로는 펭귄의 한 종류이다.
👉 뽀로로 == 하위 클래스, 펭귄 == 상위 클래스가 된다.

Interface

  • 모든 메소드추상 메소드인 경우
  • 추상 클래스보다 한 단계 더 추상화된 클래스라고 볼 수 있다.
  • 상수(static final)추상 메소드(abstract method)의 집합이다.
  • 생성자를 가질 수 없기 때문에 객체화가 불가능하다.

Java 8부터 지원되는 사항
👉 인터페이스에 디폴트 메소드(default method)를 지원한다.

디폴트 메소드의 목적 및 특징
👉 기존 인터페이스의 기능을 확장한다.
👉 디폴트 메소드 내부에 구현체 공통 기능을 작성함으로써 반복되는 코드 작성을 줄여준다.
👉 어떤 기능 추가 등 변화가 생기면, 디폴트 메소드 내부만 수정하면 되고 구현체는 수정할 필요가 없다.
👉 디폴트 메소드를 사용하기 위해서는 default 키워드를 꼭 붙여줘야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Printable {

    public abstarct void paper();

    // Default Method: 실행 내용까지 있음
    public default void setPrint(boolean color){
      if(color){
        System.out.println("컬러 출력");
      }
      else {
        System.out.println("흑백 출력");
      }
   }
}


  • 인터페이스는 다중 상속을 지원한다.
  • 따라서, 구현체에 여러 개의 인터페이스를 구현할 수 있다.

👉 클래스는 단일 상속을 지원한다. 다중 상속은 지원하지 않는다.

  • 상수는 public static final, 추상 메소드는 public abstract를 생략해도 된다.
  • 컴파일러가 컴파일 시 자동으로 생성해준다.

java_abstract_class_vs_interface_1

  • 인터페이스는 구현(implements)된다.
  • 구현은 be able to(~할 수 있는)이라는 의미를 가진다.
  • 인터페이스는 네이밍 규칙을 가지고 있는데, 보통 __able 형태로 짓는다.
  • 인터페이스 구현체도 네이밍 규칙이 있다. 보통 __Impl 형태로 짓는다.

extends, implements Keywords

  • extends: 클래스 ⬅ 클래스, 인터페이스 ⬅ 인터페이스 상속
  • implements: 인터페이스 ⬅ 클래스 상속

java_abstract_class_vs_interface_2

Same Features

  • 선언부만 있고 구현부는 없는 추상 메소드를 가진다.
  • 추상 클래스 혹은 인터페이스를 상속받은 자식 클래스에서 추상 메소드를 구현한다.
  • 결국, 자식 클래스에서 무언가 반드시 구현하도록 위임해야할 때 사용한다.

Different Features

  • 추상 클래스는 단일 상속, 인터페이스는 다중 상속이 가능하다.

java_abstract_class_vs_interface_3

  • 추상 클래스의 목적은 상속을 받아 기능을 확장시키는 것이다. (부모의 유전자를 물려받는다.)
  • 인터페이스의 목적은 구현하는 모든 클래스에 대해 특적 메소드가 반드시 존재하도록 강제하는 것이다. (부모로부터 유전자를 물려받는 게 아니다. 사교적으로 필요에 따라 결합하는 관계이다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* 동물 추상 클래스
*/
@Getter @Setter
public abstract class Animal {

	  private String name;
	  private String leg;

	  /* Abstract method */
	  abstract void run();
}

/**
* 탈 수 있는(Ridable) 인터페이스
*/
public interface Ridable {

	  /**
	  * Abstract method 
	  * @riderName
	  */
	  void youCanRide(String riderName);
}

/**
* 추상클래스를 상속 받고 인터페이스를 구현한 Horse 클래스
*/
public class Horse extends Animal implements Ridable {

	  @Override
	  public void run() {
		  System.out.println(this.getName()+"은(는) 네 발로 뛴다.");
	  }
  
	  @Override
	  public void ridable(String riderName) {
		  System.out.println(this.getName()+"은(는) "+riderName+"을(를) 태울 수 있다.");
	  } 
}

/**
* 추상클래스를 상속 받은 Kangaroo 클래스
*/
public class Kangaroo extends Animal {

	  @Override
	  public void run() {
		  System.out.println(this.getName()+"은(는) 네 발로 뛴다.");
	  }
}

public class MainClass {

	  public static void main(String[] args) {
		  Horse horse = new Horse();
          Kangaroo kangol = new Kangaroo();
    
		  /* 상속받은 말의 속성 */
		  horse.setName("얼룩말");
		  horse.setLeg("다리 4개");
    
   	      /* 상속받은 캥거루의 속성 */
		  kangol.setName("캥거루");
		  kangol.setLeg("다리 4개");
    
		  /* 말 구현체의 메서드 호출 */
   	      horse.run();
		  horse.ridable("BAEKJH");
    
	      /* 캥거루 구현체의 메서드 호출 */
		  kangol.run();
	  }
}
  • 추상 메소드: 모든 동물뛴다(run).
  • 인터페이스: 일부 동물탈 수 있다(ridable).

👉 말은 뛰고(run) 탈 수 있다(is ridable).
👉 캥거루는 뛰지만(run) 탈 수 없다(is not ridable).

References

This post is licensed under CC BY 4.0 by the author.