사용시기 : Java 8+ 인터페이스 기본 방법과 추상 방법


540

Java 8에서는 Default Methods 라는 인터페이스에서 메소드의 기본 구현을 허용합니다 .

나는 (with ) interface default method대신 언제 그런 종류의을 사용할 것인지 혼동 합니다.abstract classabstract method(s)

그렇다면 언제 기본 메소드와의 인터페이스를 사용해야하고 추상 클래스 (추상 메소드와 함께)를 사용해야합니까? 해당 시나리오에서 추상 클래스가 여전히 유용합니까?


38
아마도 추상 클래스에서는 인터페이스에 필드, 개인 메소드 등을 가질 수 없습니까?
sp00m

2
나는이 주제에 대해 이전에 궁금해했다. 지금은 명확하다. @ Narendra Pathai에게 감사한다. 두 가지 모두 의심 스럽기 때문에 동일한 주제와 관련하여 다른 스레드의 링크를 추가하고 싶습니다. stackoverflow.com/questions/19998309/…
Ashutosh Ranjan

이 게시물에서 좋은 게시물을 찾을 수 있습니다 : blog.codefx.org/java/everything-about-default-methods
Fabri Pautasso

기본 클래스에 상태가 있더라도 여전히 기본 클래스를 인터페이스로 코딩 할 수 있습니다. 인터페이스가 상태에 대한 세터와 게터를 정의해야하고 구체적인 클래스가이를 구현하고 필드를 정의해야합니다. 이에 대한 한 가지 제한 사항은 추상 클래스에서 Bean 특성이 개인용이거나 보호 될 수 있다는 것입니다. 인터페이스에는 공용 메소드 만 있습니다. 따라서 추상 기본 클래스를 사용하는 한 가지 이유는 클래스에 개인 또는 보호가 필요한 속성이있는 경우입니다.
DaBlick

@DaBlick HashMap을 통한 인터페이스의 상태 문제를 해결할 수 없었습니다. 예 : int a, b, String c를 보유하는 Foo 클래스를 원한다면 상태를 유지하려면 HashMap </ * Foo 객체의 이름 * / 문자열, / * 필드의 필드 * / Hashmap </ * 이름 특정 필드 * / 문자열, / * field value * / Object >> map을 만듭니다. . 이론적 클래스 Foo를 "인스턴스화"하려는 경우, instantiate (String nameOfFoo) 메소드는 map.put (nameOfFoo, fields)를 수행합니다. 여기서 fields는 HashMap <String, Object> fields.put ( "a", new int ( "5")); fields.put ( "b", 새로운 int ( "6")); fields.put ( "c", "blah"));
George Xavier

답변:


307

기본 메소드 구현 (예 : 개인 상태)보다 클래스를 추상화하는 것이 훨씬 더 많지만 Java 8에서 선택할 때마다 default인터페이스에서 방어자 (일명. ) 메소드 를 사용해야합니다 .

기본 메소드에 대한 제한은 특정 구현 상태를 참조하지 않고 다른 인터페이스 메소드에 대한 호출 측면에서만 구현할 수 있다는 것입니다. 따라서 주요 사용 사례는보다 높은 수준의 편리한 방법입니다.

이 새로운 기능의 장점은 편리한 메소드에 대해 추상 클래스를 사용하기 전에 구현자를 단일 상속으로 제한하기 전에 인터페이스와 최소한의 구현만으로 실제로 깨끗한 디자인을 가질 수 있다는 것입니다. 프로그래머에 대한 노력.

defaultJava 8에 메소드 를 도입하려는 원래 동기 는 기존 구현을 중단하지 않고 람다 지향 메소드로 Collections Framework 인터페이스를 확장하려는 바람이었습니다. 이것은 공공 도서관의 저자와 더 관련이 있지만 동일한 기능이 프로젝트에서도 유용하다는 것을 알 수 있습니다. 새로운 편의성을 추가 할 수있는 중앙 집중식 장소가 하나 있으며 나머지 유형 계층 구조가 어떻게 보이는지에 의존 할 필요는 없습니다.


34
이 추론에 따르면 다음에 추가 할 것은 기본 메소드 선언입니다. 나는 아직도 이것에 대해 확신하지 못한다.이 기능은 오용으로 모든 사람에게 노출되는 해킹처럼 보인다.
표범

3
내가 볼 수있는 Java 8 시대의 추상 클래스는 유일하지 않은 필드를 정의하는 것입니다. 인터페이스에서 필드는 기본적으로 최종이므로 할당 된 필드는 변경할 수 없습니다.
Anuroop

7
@Anuroop 기본적으로뿐만 아니라, 이것이 유일한 옵션입니다. 인터페이스는 인스턴스 상태를 선언 할 수 없으므로 추상 클래스가 여기에 있습니다.
Marko Topolnik

2
@PhilipRego 추상 메소드는 구현이 없기 때문에 아무것도 호출하지 않습니다. 클래스에서 구현 된 메소드는 클래스의 상태 (인스턴스 변수)에 액세스 할 수 있습니다. 인터페이스는 선언 할 수 없으므로 기본 메소드가 액세스 할 수 없습니다. 그들은 상태에 액세스하는 구현 된 메소드를 제공하는 클래스에 의존해야합니다.
Marko Topolnik

2
Marko Topolnik, 당신의 대답은 끝났습니다. 그러나 귀하의 답변에 대한 업데이트를 권장하고 싶습니다. 기본 메소드의 장점은 인터페이스가 새 기본 메소드를 추가해도 해당 인터페이스의 이전 구현이 중단되지 않는다는 것입니다. 이것은 Java 8 이전에는 사실이 아니 었습니다.
hfontanez

125

몇 가지 기술적 차이점이 있습니다. 추상 클래스는 여전히 Java 8 인터페이스와 비교하여 더 많은 작업을 수행 할 수 있습니다.

  1. 추상 클래스는 생성자를 가질 수 있습니다.
  2. 추상 클래스는 더 구조적이며 상태를 유지할 수 있습니다.

개념적으로 방어자 메소드의 주요 목적은 Java 8에서 새로운 기능 (람다 함수로)을 도입 한 후의 호환성입니다.


20
이 답변은 실제로 정확하고 특히 의미가 있습니다. "개념적으로 방어자의 주요 목적은 이전 버전과의 호환성입니다"
Trying

1
@UnKnown이 페이지는 더 많은 통찰력을 제공합니다 : docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
bernie

@UnKnown, 기본적으로 인터페이스에 메소드를 추가하고 해당 인터페이스를 구현하는 클래스가 자동으로 해당 기능을 가져옵니다.
LegendLength

3
포인트 번호에 대한 더 미묘한 포인트. 「상태를 유지할 수있다」에 대해서는 상기 2입니다. 추상 클래스는 나중에 변경 될 수있는 상태를 유지할 수 있습니다. 인터페이스는 상태를 유지할 수도 있지만 인스턴스 생성 후 상태가 할당되면 상태를 변경할 수 없습니다.
Anuroop

3
@ Anuroop public static final인터페이스 의 필드를 "상태"로 설명하지 않습니다 . 이 static부분은 특정 인스턴스와 전혀 관련이 없음을 의미합니다. 이것은 클래스 인스턴스화에 할당 되며 , 인스턴스 생성 후 와 다릅니다 .
geronimo

65

이에 대해서는이 기사 에서 설명 합니다. forEach컬렉션 에 대해 생각하십시오 .

List<?> list = 
list.forEach(…);

foreach 문은 선언되지 java.util.List않으며 java.util.Collection아직 인터페이스를 제공합니다. 확실한 해결책 중 하나는 기존 인터페이스에 새 메소드를 추가하고 JDK에서 필요한 경우 구현을 제공하는 것입니다. 그러나 일단 게시되면 기존 구현을 중단하지 않고 인터페이스에 메소드를 추가 할 수 없습니다.

기본 메소드의 이점은 이제 인터페이스에 새 기본 메소드를 추가 할 수 있으며 구현을 중단하지 않는다는 것입니다.


1
'기존 구현을 중단하지 않고 인터페이스에 메소드를 추가하는 것은 불가능합니다'-그렇지 않습니까?
Andrey Chaschev 10

26
@AndreyChaschev 인터페이스에 새 메소드를 추가하면 모든 구현자가 해당 새 메소드를 구현해야합니다. 따라서 기존 구현이 중단됩니다.
Marko Topolnik

4
@MarkoTopolnik 감사합니다. 이 방법을 기본 추상 구현으로 제시함으로써 이것을 부분적으로 피할 수 있는 방법 이 있습니다. 이 예제에서는을 AbstractList::forEach던집니다 UnsupportedOperationException.
Andrey Chaschev 10

3
@AndreyChaschev 그렇습니다. 구식자가 제공된 추상 구현에서 단일 상속으로 제한하는 결함 이있는 오래된 방법 (khm ... 은 현재 방법 :)입니다.
Marko Topolnik

미리 그렇게되면 모든 구현에 해당 메소드가 포함되어 있으면 중단되지 않습니다. 가능성은 없지만 가능합니다.
George Xavier

19

이 두 가지는 매우 다릅니다.

기본 방법은 상태를 변경하지 않고 기존 클래스에 외부 기능추가 하는 것입니다.

그리고 추상 클래스는 일반적인 상속 유형이며, 확장하려는 일반 클래스 입니다.


18

기사 에서 설명했듯이

Java 8의 추상 클래스와 인터페이스

기본 메소드를 도입 한 후 인터페이스와 추상 클래스가 동일한 것 같습니다. 그러나 Java 8에서는 여전히 다른 개념입니다.

추상 클래스는 생성자를 정의 할 수 있습니다. 그것들은 더 구조적이고 그들과 관련된 상태를 가질 수 있습니다. 대조적으로, 기본 메소드는 특정 구현 상태를 참조하지 않고 다른 인터페이스 메소드를 호출하는 측면에서만 구현 될 수 있습니다. 따라서 서로 다른 목적으로 사용하고 두 가지 중에서 선택하는 것은 실제로 시나리오 상황에 따라 다릅니다.


Abstract 클래스에는 Interface와 달리 정의 할 수있는 생성자가 있다고 생각합니다. Java 8에서도 이것으로 인해 서로 다릅니다.
Hemanth Peela 19

1
추상 클래스가 인스턴스화 할 수없는 경우 왜 생성자가 있습니까?
George Xavier

추상 클래스의 생성자를 호출하는 자식 클래스에서 super ()를 호출 할 수 있습니다. 이것은 추상 클래스의 상태에 영향을줍니다.
Sujay Mohan

14

의 검색어에 대해

그렇다면 언제 기본 메소드와의 인터페이스를 사용해야하고 언제 추상 클래스를 사용해야합니까? 해당 시나리오에서 추상 클래스가 여전히 유용합니까?

자바 문서 는 완벽한 답변을 제공합니다.

인터페이스와 비교 한 추상 클래스 :

추상 클래스는 인터페이스와 유사합니다. 인스턴스화 할 수 없으며 구현 여부에 관계없이 선언 된 여러 메소드를 포함 할 수 있습니다.

그러나 추상 클래스를 사용하면 정적 및 최종이 아닌 필드를 선언하고 공개, 보호 및 개인 콘크리트 메소드를 정의 할 수 있습니다.

인터페이스를 사용하면 모든 필드가 자동으로 공개, 정적 및 최종이며, 선언하거나 정의한 모든 메소드 (기본 메소드)는 공개입니다. 또한 추상적이든 아니든 하나의 클래스 만 확장 할 수 있지만 여러 인터페이스를 구현할 수 있습니다.

이들 각각의 사용 사례는 아래 SE 게시물에 설명되어 있습니다.

인터페이스와 추상 클래스의 차이점은 무엇입니까?

해당 시나리오에서 추상 클래스가 여전히 유용합니까?

예. 그들은 여전히 ​​유용합니다. 그들은 비 정적이 아닌 마지막 방법을 포함 할 수 있습니다 및 특성 ( 보호, 공공뿐만 아니라 민간 에도 자바-8 인터페이스)로 이용 가능합니다.


이제 인터페이스가 개인 방법이 너무 howtodoinjava.com/java9/java9-private-interface-methods
valijon

13

추상 클래스와 인터페이스를 선택할 때마다 항상 (거의) 기본 (수비수 또는 가상 확장이라고도 함) 방법을 선호해야합니다.

  1. 기본 메소드는 클래식 인터페이스 패턴과 해당 인터페이스에서 대부분 또는 모든 메소드를 구현하는 동반자 클래스를 종료했습니다. 예는 Collection and AbstractCollection입니다. 이제 기본 기능을 제공하기 위해 인터페이스 자체에서 메소드를 구현해야합니다. 인터페이스를 구현하는 클래스는 메소드를 대체하거나 기본 구현을 상속하도록 선택할 수 있습니다.
  2. 기본 방법의 또 다른 중요한 용도는 interface evolution입니다. 내가 다음과 같이 공을 가지고 있다고 가정 해보십시오.

    public class Ball implements Collection { ... }

이제 Java 8에서는 새로운 기능이 도입되었습니다. stream인터페이스에 추가 된 메소드 를 사용하여 스트림을 얻을 수 있습니다 . stream기본 방법이 아닌 경우 Collection인터페이스에 대한 모든 구현은이 새로운 방법을 구현하지 않기 때문에 실패했을 것입니다. 기본이 아닌 메소드를 인터페이스에 추가하는 것은 아닙니다 source-compatible.

그러나 클래스를 다시 컴파일하지 않고이 클래스를 포함하는 오래된 jar 파일을 사용한다고 가정 해보십시오 Ball. 이 누락 된 메소드없이 클래스가 정상적으로로드되고 인스턴스를 만들 수 있으며 모든 것이 잘 작동하는 것 같습니다. 그러나 프로그램이 stream인스턴스를 호출하면 메소드를 Ball얻습니다 AbstractMethodError. 따라서 방법을 기본값으로 설정하면 두 가지 문제가 해결되었습니다.


9

Java 인터페이스의 기본 메소드로 인터페이스 진화 가능 합니다.

기존 인터페이스가 제공되는 경우, 이전 버전의 인터페이스와의 이진 호환성을 유지하면서 메소드를 추가하려면 기본 또는 정적 메소드를 추가하십시오. 실제로, 인터페이스에 추가 된 추상 메소드는이 인터페이스를 구현하는 클래스 또는 인터페이스에 의해 구현되어야합니다.

정적 메소드는 클래스에 고유합니다. 기본 메소드는 클래스 인스턴스에 고유합니다.

기존 인터페이스에 기본 메소드를 추가하면이 인터페이스를 구현하는 클래스와 인터페이스가이를 구현할 필요가 없습니다. 그들은 할 수있다

  • 기본 메소드를 구현하고 구현 된 인터페이스의 구현을 대체합니다.
  • 추상적으로 만드는 메소드 (구현없이)를 다시 선언하십시오.
  • 아무것도하지 마십시오 (그런 다음 구현 된 인터페이스의 기본 메소드는 단순히 상속됩니다).

여기 에서 주제에 대한 추가 정보 .


7

오래된 질문이지만 그것에 대한 의견도 제시하겠습니다.

  1. 추상 클래스 : 추상 클래스 내에서 우리는 자식 클래스에 필요한 인스턴스 변수를 선언 할 수 있습니다

    인터페이스 : 인터페이스 내에서 모든 변수는 항상 공개 정적이며 인스턴스 변수를 선언 할 수 없습니다

  2. 추상 클래스 : 추상 클래스는 객체의 상태에 대해 이야기 할 수 있습니다

    인터페이스 : 인터페이스는 객체 상태에 대해 이야기 할 수 없습니다

  3. 추상 클래스 : 추상 클래스 내부에서 생성자를 선언 할 수 있습니다

    인터페이스 : 인터페이스 내에서 생성자의 목적은
    인스턴스 변수를 초기화하는 것이므로 생성자를 선언 할 수 없습니다 . 인터페이스에 인스턴스 변수를 가질 수없는 경우 생성자가 필요합니다 .

  4. 추상 클래스 : 추상 클래스 내부에서 인스턴스와 정적 블록을 선언 할 수 있습니다

    인터페이스 : 인터페이스는 인스턴스 및 정적 블록을 가질 수 없습니다.

  5. 추상 클래스 : 추상 클래스는 람다 식을 참조 할 수 없습니다

    인터페이스 : 단일 추상 메소드가있는 인터페이스는 람다 식을 참조 할 수 있음

  6. 추상 클래스 : 안에서 OBJECT CLASS 메소드를 재정의 할 수 있습니다

    인터페이스 : 인터페이스 내에서 OBJECT CLASS 메소드를 대체 할 수 없습니다.

나는 다음과 같은 메모로 끝날 것이다.

인터페이스의 기본 메소드 개념 / 정적 메소드 개념은 구현 클래스를 저장하기위한 것이지만 의미있는 유용한 구현을 제공하지는 않았습니다. 기본 메소드 / 정적 메소드는 일종의 더미 구현입니다. "원하는 경우 또는 구현 클래스에서 기본 메소드의 경우 메소드를 대체 할 수 있습니다" 인터페이스의 새 메소드가있을 때마다 구현 클래스에서 새 메소드를 구현하지 않아도 추가됩니다. 따라서 인터페이스는 절대 추상 클래스와 같을 수 없습니다.


5

Remi Forax 규칙은 추상 클래스로 디자인하지 않는다는 것입니다. 인터페이스를 사용하여 앱을 디자인합니다 . Watever는 언어에 관계없이 Java 버전입니다. 그것은 지원을받습니다 I의 nterface의 분리 원칙SOL I D의 원칙.

나중에 추상 클래스를 사용하여 코드를 분해 할 수 있습니다. 이제 Java 8을 사용하면 인터페이스에서 직접 수행 할 수 있습니다. 이것은 더 이상 시설이 아닙니다.


2

언제 기본 메소드와의 인터페이스를 사용해야하고 언제 추상 클래스를 사용해야합니까?

이전 버전과의 호환성 : 인터페이스가 수백 개의 클래스로 구현되고 인터페이스를 수정하면 인터페이스를 구현하는 다른 많은 클래스에 필수적인 것은 아니지만 모든 사용자가 새로 추가 된 메소드를 강제로 실행한다고 상상해보십시오 .기능적 인터페이스

사실 및 제한 사항 :

1- 클래스 또는 추상 클래스가 아닌 인터페이스 내에서만 선언 될 수 있습니다.

2- 몸을 제공해야 함

3- 인터페이스에서 사용되는 다른 일반적인 방법과 같이 추상적이라고 가정하지 않습니다.


1

Java 8에서 인터페이스는 다음과 같은 차이점이 있지만 추상 클래스처럼 보입니다.

1) 추상 클래스는 클래스이므로 Java의 인터페이스에 대한 다른 제한으로 제한되지 않습니다. 예를 들어 추상 클래스 는 상태를 가질 수 있습니다. state를 가질 수 있지만 Java 인터페이스의 상태는 가질 수 없습니다.

2) 기본 메소드가있는 인터페이스와 추상 클래스의 또 다른 의미 차이는 추상 클래스 안에 생성자를 정의 할 수 있지만 Java에서 인터페이스 내부에 생성자를 정의 할 수 없다는 것입니다


# 2에 동의하지만 # 1에 대해서는 인터페이스를 구현할 수 없으므로 구현 클래스를 통해 상태를 가질 수 있습니까?
George Xavier

0

Java 인터페이스의 기본 메소드는 함수의 더미 구현을 제공하기 위해 더 많이 사용되므로 모든 추상 메소드를 하나만 처리하려는 경우에도 모든 추상 메소드를 선언하는 고통에서 해당 인터페이스의 구현 클래스를 절약 할 수 있습니다. 따라서 인터페이스의 기본 메소드는 어댑터 클래스 개념을 대체합니다.

그러나 추상 클래스의 메소드는 모든 하위 클래스가 공통 기능을 대체해야하는 경우에만 대체해야하는 의미있는 구현을 제공해야합니다.


0

다른 답변에서 언급했듯이 Collections 프레임 워크에서 이전 버전과의 호환성을 제공하기 위해 인터페이스에 구현을 추가하는 기능이 추가되었습니다. 역 호환성을 제공하는 것이 인터페이스에 구현을 추가하는 유일한 이유라고 주장합니다.

그렇지 않으면 인터페이스에 구현을 추가하면 인터페이스가 처음에 추가 된 이유에 대한 기본 법칙을 위반하는 것입니다. Java는 다중 상속을 허용하는 C ++과 달리 단일 상속 언어입니다. 인터페이스는 다중 상속에 따른 문제를 유발하지 않고 다중 상속을 지원하는 언어와 함께 제공되는 타이핑 이점을 제공합니다.

보다 구체적으로, Java는 구현의 단일 상속 만 허용하지만 인터페이스의 다중 상속은 허용합니다. 예를 들어, 다음은 유효한 Java 코드입니다.

class MyObject extends String implements Runnable, Comparable { ... }

MyObject 하나의 구현 만 상속하지만 세 개의 계약을 상속합니다.

Java는 다중 상속 상속을 전달했습니다. 여러 상속 상속에는이 답변의 범위를 벗어난 수많은 문제가 있기 때문입니다. 다중 구현 상속 문제없이 계약의 다중 상속 (인터페이스)을 허용하는 인터페이스가 추가되었습니다.

내 요점을 뒷받침하기 위해 책 The Java Programming Language, 4th edition의 Ken Arnold와 James Gosling의 인용문이 있습니다 .

단일 상속은 유용하고 정확한 디자인을 배제합니다. 다중 상속의 문제는 구현의 다중 상속에서 발생하지만 많은 경우 다중 상속은 여러 추상 계약과 하나의 구체적인 구현을 상속하는 데 사용됩니다. 구현을 상속하지 않고 추상 계약을 상속 할 수있는 방법을 제공하면 다중 구현 상속 문제없이 다중 상속의 타이핑 이점을 얻을 수 있습니다. 추상 계약의 상속을 인터페이스 상속 이라고 합니다. Java 프로그래밍 언어는 interface유형 을 선언 할 수 있도록하여 인터페이스 상속을 지원 합니다.


-1

개방 / 폐쇄 원칙을 먼저 생각하십시오. 인터페이스의 기본 메소드는이를 위반합니다. 이것은 Java의 나쁜 기능입니다. 나쁜 디자인, 나쁜 아키텍처, 낮은 소프트웨어 품질을 권장합니다. 기본 방법을 완전히 사용하지 않는 것이 좋습니다.

몇 가지 질문을 해보십시오. 왜 메소드를 추상 클래스에 넣을 수 없습니까? 그런 다음 둘 이상의 추상 클래스가 필요합니까? 그런 다음 반원이 무엇을 책임 지는지 생각해보십시오. 단일 클래스에 넣을 모든 메소드가 실제로 동일한 목적을 달성한다고 확신합니까? 여러 목적을 구분 한 다음 각 목적에 따라 클래스를 여러 클래스로 분할 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.