JAVA

15. Default Method & 추상 클래스 & 인터페이스

ggomjiu 2025. 4. 29. 01:58

Default Method

1. 개요

- 배포된 인터페이스에서 수정이 어려운 단점을 극복하게 됨

- Java 9) private Method를 선언해 외부에서 접근 불가능한 mehtod 또한 선언할 수 있게 됨

- EX)

interface Foo {

  String getName(); // 추상 메서드, 구현하는 클래스에서 무조건 구현해줘야 하는 메서드.

}

---

public class Bar implements Foo {
  private String name;

  public Bar(String name) { // 생성자
    this.name = name;
  }

  @Override
  public String getName() { // 추상 메서드 구현
    return this.name;
  }
}

---

public class Main {
  public static void main(String[] args) {
    Foo foo = new Bar("Neo");
    System.out.println(foo.getName());
  }
}

---

Result

>> Neo

- 이전의 방식 ) 인터페이스에 새로운 printName() 메서드를 추가하고 인터페이스 Foo를 구현한 모든 클래스에서 새로운 메서드를 구현했어야 함

- Default Method EX)

interface Foo {

  String getName(); // 추상 메서드, 구현하는 클래스에서 무조건 구현해줘야 하는 메서드.

  void printName() {
    System.out.println(getName());
  }

}

---

public class Bar implements Foo {
  private String name;

  public Bar(String name) { // 생성자
    this.name = name;
  }

  @Override
  public String getName() { // 추상 메서드 구현
    return this.name;
  }
}

---

public class Main {
  public static void main(String[] args) {
    Foo foo = new Bar("Neo");
    foo.printName();
  }
}

---

Result

>> Neo

 

2. 주의

- 다중 상속시 같은 이름의 메서드가 두 인터페이스에 모두 존재할 때, 구현 클래스에서 재정의해서 사용해야 함

- EX)

interface Foo {
  void sameNameMethod();
}

---

interface Bar {
  void sameNameMethod();
}

---

class Impl implements Foo, Bar {
  ...
}

---

public class Main {
  public static void main(String[] args) {
    Impl impl = new Impl();
    impl.sameNameMethod(); // 모른다! 메서드! 뱉어낸다! 에러!
  }
}

---

Result

>> Error : Main inherits unrelated defaults...

- 구현하는 클래스에서 메서드를 재정의해서 사용해야 함

interface Foo {
  void sameNameMethod();
}

---

interface Bar {
  void sameNameMethod();
}

---

class Impl implements Foo, Bar {
  @Override
  publci void sameNameMethod() {
    System.out.println("sameNameMethod called!");
  }
}

---

public class Main {
  public static void main(String[] args) {
    Impl impl = new Impl();
    impl.sameNameMethod(); // 안다! 메서드! 뱉어낸다! 결과!
  }
}

---

Result

>> sameNameMethod called!
  • 디폴트 메서드는 equals(), hashcode()와 같은 Object 클래스의 메서드를 재정의 할 수 없음
  • 정적 메서드는 재정의 할 수 없음
  • 인터페이스 간 상속관계에 따라 우선순위가 달라짐
    • IF) interface A extends B처럼 인터페이스 A가 B를 상속받고, B에서 정의된 디폴트 메서드를 재정의 할 경우, A의 디폴트 메서드가 우선순위를 가짐
    • IF) class C implements A처럼 A가 B를 상속받고, 그 상속받은 인터페이스를 C가 구현해 디폴트 메서드를 재정의 한 경우, C의 재정의된 메서드가 우선권을 가짐

추상 클래스 vs 인터페이스

- 추상 클래스와 인터페이스는 쓰임이 다름

1. 공통점

  • 스스로 new 연산자를 통해 객체를 생성할 수 없음
  • 추상 메서드를 가짐
  • 자손 클래스를 이용해 정의된 추상 메서드들을 구현해야 함

2. 용도, 태생

- 추상 클래스

  • 여러 클래스를 추상화해 공통점을 묶은 추상 클래스를 상속받아 그 기능을 사용하거나 확장하기 위함

- 인터페이스

  • 여러 구현체들의 맥락에 맞는 동일한 동작을 보장하기 위한 명세

3. 다중 상속 가능 여부

- 추상 클래스

  • 다중 상속 불가능

- 인터페이스

  • 다중 상속 가능

4. 선언 가능한 메서드

- 추상 클래스

  • 일반 클래스와 동일하고, 추상 메서드를 선언할 수 있음

- 인터페이스

  • 추상 메서드만 선언할 수 있었으마, Java8부터 디폴트 메서드, Java9부터 정적 메서드까지 선언 가능하게 됨

5. 변수와 생성자, 메서드

- 추상 클래스

  • 생성자, 변수, 메서드를 모두 가질 수 있음

- 인터페이스

  • 메서드와 정적 상수만 가질 수 있음
  • Java8 이전까지는 추상 메서드만, Java9 이전까지는 추상 메서드 + 디폴트 메서드, 그 이후로는 추상 메서드 + 디폴트 메서드 + private메서드만 가질 수 있음

6. 자식 클래스에서의 구현의 강제성

- 추상 클래스

  • 선택적으로 오버라이딩 가능

- 인터페이스

  • 정의된 모든 추상 메서드를 구현해야 함
  • 디폴트 메서드의 경우 선택적으로 구현 가능

7. 키워드

- 추상 클래스

  • extends

- 인터페이스

  • implements