내 이해에 따르면 Java에서 인터페이스를 구현하는 경우 해당 인터페이스에 지정된 메서드는 해당 인터페이스를 구현하는 하위 클래스에서 사용해야합니다.
Collection 인터페이스와 같은 일부 인터페이스에는 선택 사항으로 주석 처리 된 메서드가 있지만 이것이 정확히 무엇을 의미합니까? 인터페이스에 지정된 모든 메서드가 필요하다고 생각했기 때문에 조금 던졌습니다.
내 이해에 따르면 Java에서 인터페이스를 구현하는 경우 해당 인터페이스에 지정된 메서드는 해당 인터페이스를 구현하는 하위 클래스에서 사용해야합니다.
Collection 인터페이스와 같은 일부 인터페이스에는 선택 사항으로 주석 처리 된 메서드가 있지만 이것이 정확히 무엇을 의미합니까? 인터페이스에 지정된 모든 메서드가 필요하다고 생각했기 때문에 조금 던졌습니다.
답변:
여기에 대한 답변에 끔찍한 혼란이있는 것 같습니다.
Java 언어에서는 인터페이스의 모든 메소드가 해당 인터페이스의 모든 구현에 의해 구현되어야합니다. 기간. 이 규칙에는 예외가 없습니다. "컬렉션은 예외입니다"라는 말은 여기서 실제로 일어나는 일에 대한 매우 모호한 이해를 의미합니다.
인터페이스를 준수하는 데는 두 가지 수준이 있다는 것을 인식하는 것이 중요합니다.
Java 언어로 확인할 수있는 항목. 이것은 꽤 많은 단지로 귀결이 어떤 방법 각각에 대한 구현은?
실제로 계약을 이행했습니다. 즉, 구현이 인터페이스의 문서에 명시된대로 수행합니까?
잘 작성된 인터페이스에는 구현에서 예상되는 것을 정확히 설명하는 문서가 포함됩니다. 컴파일러는 이것을 확인할 수 없습니다. 문서를 읽고 그들이 말하는대로해야합니다. 계약서에 명시된대로 수행하지 않으면 컴파일러 에 관한 한 인터페이스 구현 이 가능하지만 결함 / 잘못된 구현이됩니다.
컬렉션 API를 디자인 할 때 Joshua Bloch는 컬렉션의 다양한 변형 (예 : 읽기 가능, 쓰기 가능, 임의 액세스 등)을 구별하기 위해 매우 세밀한 인터페이스를 사용하는 대신 매우 조잡한 인터페이스 세트 만 사용하기로 결정했습니다.
Collection
, List
, Set
그리고 Map
다음 "선택"과 같은 특정 작업을 문서화합니다. 이는 세분화 된 인터페이스로 인해 발생할 수있는 조합 적 폭발을 방지하기위한 것입니다. 로부터 자바 컬렉션 API 디자인 자주 묻는 질문 :
문제를 자세히 설명하기 위해 계층 구조에 수정 가능성 개념을 추가한다고 가정합니다. ModifiableCollection, ModifiableSet, ModifiableList 및 ModifiableMap의 네 가지 새 인터페이스가 필요합니다. 이전에 단순한 계층이었던 것이 이제는 지저분한 계층이되었습니다. 또한 제거 작업을 포함하지 않는 수정 불가능한 컬렉션과 함께 사용할 새 Iterator 인터페이스가 필요합니다. 이제 UnsupportedOperationException을 제거 할 수 있습니까? 불행히도.
배열을 고려하십시오. 대부분의 List 작업을 구현하지만 제거 및 추가는 수행하지 않습니다. 그들은 "고정 크기"목록입니다. 계층 구조에서이 개념을 캡처하려면 VariableSizeList 및 VariableSizeMap이라는 두 개의 새 인터페이스를 추가해야합니다. VariableSizeCollection 및 VariableSizeSet은 ModifiableCollection 및 ModifiableSet과 동일하므로 추가 할 필요가 없지만 일관성을 위해 추가하도록 선택할 수 있습니다. 또한 수정 불가능한 List와 함께 이동하려면 추가 및 제거 작업을 지원하지 않는 새로운 다양한 ListIterator가 필요합니다. 이제 우리는 원래 4 개 대신 최대 10 개 또는 12 개의 인터페이스와 2 개의 새로운 Iterator 인터페이스가 있습니다. 끝났어? 아니.
로그 (예 : 복구 가능한 데이터 개체에 대한 오류 로그, 감사 로그 및 저널)를 고려합니다. 제거 및 설정 (바꾸기)을 제외한 모든 List 작업을 지원하는 자연스러운 추가 전용 시퀀스입니다. 새로운 핵심 인터페이스와 새로운 반복자가 필요합니다.
그리고 수정 불가능한 콜렉션과 달리 불변의 콜렉션은 어떻습니까? (즉, 클라이언트가 변경할 수없고 다른 이유로 변경되지 않는 컬렉션). 많은 스레드가 동기화없이 컬렉션에 동시에 액세스 할 수 있기 때문에 이것이 가장 중요한 차이점이라고 주장합니다. 이 지원을 유형 계층 구조에 추가하려면 인터페이스가 4 개 더 필요합니다.
이제 우리는 최대 20 개 정도의 인터페이스와 5 개의 반복자이며, 실제로 어떤 인터페이스에도 깔끔하게 맞지 않는 컬렉션이 실제로 발생하는 것이 거의 확실합니다. 예를 들어 Map에서 반환하는 컬렉션 뷰는 자연적인 삭제 전용 컬렉션입니다. 또한 값을 기준으로 특정 요소를 거부하는 컬렉션이 있으므로 런타임 예외를 처리하지 않았습니다.
모든 것을 말하고 완료했을 때, 우리는 런타임 예외를 던질 수있는 매우 작은 핵심 인터페이스 세트를 제공함으로써 전체 문제를 회피하는 것이 건전한 엔지니어링 타협이라고 느꼈습니다.
Collections API의 메서드가 "선택적 작업"으로 문서화되어 있다고해서 메서드 구현을 구현에서 제외 할 수 있다는 의미도 아니며 빈 메서드 본문을 사용할 수 있다는 의미도 아닙니다. 결과를 반환해야합니다). 오히려 유효한 구현 선택 (여전히 계약을 준수하는)은 UnsupportedOperationException
.
그 때문에 참고 UnsupportedOperationException
A는 RuntimeException
당신이 멀리 컴파일러에 관한 한, 어떤 메소드 구현에서 던질 수 있습니다. 예를 들어, Collection.size()
. 그러나 이러한 구현은 문서에 Collection.size()
이것이 허용된다고 명시 되어 있지 않으므로 계약을 위반하게 됩니다.
곁에 : Java의 Collections API가 사용하는 접근 방식은 다소 논란의 여지가 있습니다 (하지만 처음 도입되었을 때보 다 지금은 적을 것입니다). 완벽한 세상에서는 인터페이스에 선택적 작업 이 없으며 대신 세분화 된 인터페이스가 사용됩니다. 문제는 Java가 유추 된 구조 유형이나 교차 유형을 지원하지 않는다는 것입니다. 이것이 바로 컬렉션의 경우 "올바른 방법"으로 작업을 시도하는 것이 극도로 다루기 힘들어지는 이유입니다.
There are no exceptions to this rule
. 이 답변이 수락 된 것으로 표시되지 않은 이유가 궁금합니다. 다른 것들은 좋지만 당신은 충분히 많이 주셨습니다.
Foo
구현하지 않는 생성 . 이제 클래스 생성 그 와 overiding없이를 . 간접적이기는하지만 여전히 메서드를 구현합니다. 마찬가지로 기본 메서드 구현은 여전히 구현입니다. Runnable
void run()
Bar
extends Foo
implements Runnable
run
remove
에서 기본 구현이 제공 되었기 때문입니다 . 구현하지 않으면 클래스가 기본 구현을 가져옵니다. 언급 한 다른 두 가지 방법에는 기본 구현이 없습니다.
인터페이스에 대한 구현 (비추 상) 클래스를 컴파일하려면 모든 메서드를 구현해야합니다.
그러나 구현이 단순한 예외 인 메소드를 '구현되지 않은'( Collection
인터페이스의 일부 메소드처럼 )으로 생각하면 Collection
인터페이스는 일반적인 경우가 아니라이 경우 예외입니다. 일반적 으로 구현하는 클래스는 모든 메소드를 구현해야합니다.
컬렉션의 "선택 사항"은 구현 클래스가 (위의 용어에 따라)이를 '구현'할 필요가 없으며 그냥 던질 것임을 의미 NotSupportedException
합니다.
좋은 예 add()
-불변 컬렉션에 대한 방법-콘크리트는 던지는 것 외에는 아무것도하지 않는 방법을 구현합니다.NotSupportedException
이 경우에는 Collection
복잡한 상속 트리를 방지하기 위해 수행되어 프로그래머를 비참하게 만들지 만 대부분의 경우이 패러다임은 권장되지 않으며 가능하면 피해야합니다.
최신 정보:
Java 8부터 기본 메소드 가 도입되었습니다.
즉, 인터페이스는 구현을 포함하여 메소드를 정의 할 수 있습니다.
이것은 인터페이스에 기능을 추가하는 동시에 새로운 기능이 필요하지 않은 코드 부분에 대해 이전 버전과의 호환성을 지원하기 위해 추가되었습니다.
메서드는 선언하는 모든 클래스에서 여전히 구현되지만 인터페이스의 정의를 사용합니다.
Java의 인터페이스는 클래스 구현 계약을 선언합니다. 해당 인터페이스의 모든 메서드는 구현 되어야 하지만 구현 클래스는 구현되지 않은 상태로 남겨 둘 수 있습니다. 인위적인 예로서
interface Foo {
void doSomething();
void doSomethingElse();
}
class MyClass implements Foo {
public void doSomething() {
/* All of my code goes here */
}
public void doSomethingElse() {
// I leave this unimplemented
}
}
이제 doSomethingElse()
구현되지 않은 상태로 두어 서브 클래스가 구현할 수 있도록 무료로 남겨 둡니다. 그것은 선택 사항입니다.
class SubClass extends MyClass {
@Override
public void doSomethingElse() {
// Here's my implementation.
}
}
그러나 다른 사람들이 말했듯이 컬렉션 인터페이스에 대해 이야기하는 경우 예외입니다. 특정 메서드가 구현되지 않은 상태로 유지되고이를 호출하면 UnsupportedOperationException
예외 가 발생할 수 있습니다 .
Collection 인터페이스의 선택적 메서드는 메서드 구현에서 예외를 throw 할 수 있지만 어쨌든 구현해야 함을 의미합니다. 문서에 지정된대로 :
일부 컬렉션 구현에는 포함 할 수있는 요소에 대한 제한이 있습니다. 예를 들어, 일부 구현에서는 null 요소를 금지하고 일부 구현에는 요소 유형에 대한 제한이 있습니다. 부적합한 요소를 추가하려고하면 일반적으로 NullPointerException 또는 ClassCastException과 같은 확인되지 않은 예외가 발생합니다. 부적합한 요소가 있는지 쿼리하려고하면 예외가 발생하거나 단순히 false를 반환 할 수 있습니다. 일부 구현은 전자의 동작을 나타내고 일부는 후자를 나타냅니다. 보다 일반적으로, 완료로 인해 부적격 요소가 컬렉션에 삽입되지 않는 부적격 요소에 대한 작업을 시도하면 구현 옵션에 따라 예외가 발생하거나 성공할 수 있습니다. 이러한 예외는 "선택 사항"으로 표시됩니다.
new Runnable ( ) { @ Override public void run ( ) { throw new UnsupportedOperationException ( ) ; } }
;
사실 저는 SurfaceView.Callback2에서 영감을 받았습니다. 이것이 공식적인 방법이라고 생각합니다
public class Foo {
public interface Callback {
public void requiredMethod1();
public void requiredMethod2();
}
public interface CallbackExtended extends Callback {
public void optionalMethod1();
public void optionalMethod2();
}
private Callback mCallback;
}
클래스가 선택적 메서드를 구현할 필요가없는 경우 "콜백 구현"만하면됩니다. 클래스가 선택적 메서드를 구현해야하는 경우 "CallbackExtended를 구현"하면됩니다.
똥 영어 죄송합니다.
Java 8 이상에서이 질문에 대한 대답은 여전히 유효하지만 이제는 더 미묘합니다.
첫째, 수락 된 답변의 다음 진술은 정확합니다.
그렇다면 Java 8의 새로운 뉘앙스는 무엇입니까? "선택적 방법"에 대해 말할 때 다음 중 하나가 적합합니다.
1. 계약 상 선택적 구현 방법
"세 번째 진술"은 추상 인터페이스 메소드가 항상 구현되어야하며 이는 Java 8+에서도 여전히 적용된다는 것을 말합니다. 그러나 Java Collections Framework에서와 같이 일부 추상 인터페이스 메소드를 계약에서 "선택 사항"으로 설명 할 수 있습니다.
이 경우 인터페이스를 구현하는 작성자는 메서드를 구현하지 않도록 선택할 수 있습니다. 그러나 컴파일러는 구현을 주장하므로 작성자는 특정 구현 클래스에서 필요하지 않은 선택적 메서드에 대해이 코드를 사용합니다.
public SomeReturnType optionalInterfaceMethodA(...) {
throw new UnsupportedOperationException();
}
Java 7 및 이전 버전에서 이것은 실제로 존재하는 유일한 "선택적 메소드"였습니다. 즉, 구현되지 않은 경우 UnsupportedOperationException을 발생시키는 메소드였습니다. 이 동작은 반드시 인터페이스 계약 (예 : Java Collections Framework의 선택적 인터페이스 메서드)에 의해 지정됩니다.
2. 재 구현이 선택적인 기본 방법
Java 8은 기본 메소드 개념을 도입했습니다 . 이들은 인터페이스 정의 자체에 의해 구현 될 수 있고 제공되는 메소드입니다. 일반적으로 메서드 본문이 다른 인터페이스 메서드 (예 : "프리미티브")를 사용하여 작성 될 수 있고 " this
클래스가이 인터페이스를 구현 한이 객체"를 의미 할 수있는 경우에만 기본 메서드를 제공 할 수 있습니다 .
기본 메소드는 인터페이스의 계약을 이행해야합니다 (다른 인터페이스 메소드 구현과 마찬가지로). 따라서 구현 클래스에서 인터페이스 메서드의 구현을 지정하는 것은 작성자의 재량입니다 (동작이 자신의 목적에 적합한 경우).
이 새로운 환경에서 Java Collections Framework 는 다음 과 같이 다시 작성할 수 있습니다 .
public interface List<E> {
:
:
default public boolean add(E element) {
throw new UnsupportedOperationException();
}
:
:
}
이런 식으로 "선택적"메서드 add()
는 구현 클래스가 자체적으로 새로운 동작을 제공하지 않는 경우 UnsupportedOperationException을 던지는 기본 동작을 갖습니다. 이는 정확히 발생하고 싶은 동작이고 List 계약을 준수합니다. 작성자가 새 요소를 List 구현에 추가 할 수없는 클래스를 작성하는 add()
경우 기본 동작이 정확히 필요한 것이기 때문에의 구현 은 선택 사항입니다.
이 경우 메서드가 인터페이스 자체에서 구현 되었기 때문에 위의 "세 번째 문"은 여전히 유효합니다.
3. Optional
결과 를 반환하는 메서드
마지막으로 새로운 종류의 선택적 메서드는 단순히 Optional
. 이 Optional
클래스는 null
결과 를 처리하는보다 객체 지향적 인 방법을 제공 합니다.
새로운 Java Streams API로 코딩 할 때 흔히 볼 수있는 것과 같은 유창한 프로그래밍 스타일에서, 어떤 시점에서든 null 결과는 프로그램이 NullPointerException과 함께 충돌하게합니다. 이 Optional
클래스는 클라이언트 코드가 충돌하지 않고 유창한 스타일을 가능하게하는 방식으로 클라이언트 코드에 null 결과를 반환하는 메커니즘을 제공합니다.
모든 컬렉션 구현의 조상 클래스 인 grepCode에서 AbstractCollection.java 의 코드를 살펴보면 선택적 메소드의 의미를 이해하는 데 도움이 될 것입니다. 다음은 AbstractCollection 클래스의 add (e) 메서드에 대한 코드입니다. 컬렉션 인터페이스 에 따라 add (e) 메서드는 선택 사항입니다.
public boolean add(E e) {
throw new UnsupportedOperationException();
}
선택적 메서드는 이미 조상 클래스에서 구현되었으며 호출시 UnsupportedOperationException이 발생 함을 의미합니다. 컬렉션을 수정할 수있게하려면 컬렉션 인터페이스 의 선택적 메서드를 재정의해야합니다 .
글쎄요,이 주제는 ... 예 ..하지만 생각하세요, 하나의 답이 없습니다. 나는 인터페이스의 "기본 방법"에 대해 이야기하고 있습니다. 예를 들어, 소멸자 등 무엇이든 닫기위한 클래스가 있다고 가정 해 봅시다. 3 가지 방법이 있어야한다고 가정 해 봅시다. "doFirst ()", "doLast ()"및 "onClose ()"라고 부르겠습니다.
그래서 우리는 그 유형의 객체가 적어도 "onClose ()"를 실현하기를 원한다고 말하지만 다른 것은 선택 사항입니다.
인터페이스의 "기본 메소드"를 사용하면이를 알 수 있습니다. 나는 이것이 대부분의 경우 인터페이스의 이유를 부정하지만 프레임 워크를 디자인하는 경우 유용 할 수 있습니다.
따라서 이런 식으로 실현하고 싶다면 다음과 같이 보일 것입니다.
public interface Closer {
default void doFirst() {
System.out.print("first ... ");
}
void onClose();
default void doLast() {
System.out.println("and finally!");
}
}
예를 들어 "Test"라는 클래스에서 구현하면 컴파일러는 다음과 같이 완벽하게 작동합니다.
public class TestCloser implements Closer {
@Override
public void onClose() {
System.out.print("closing ... ");
}
}
출력 :
first ... closing ... and finally!
또는
public class TestCloser implements Closer {
@Override
public void onClose() {
System.out.print("closing ... ");
}
@Override
public void doLast() {
System.out.println("done!");
}
}
출력 :
first ... closing ... done!
모든 조합이 가능합니다. "default"가있는 것은 무엇이든 구현할 수 있지만 구현해서는 안되지만 그렇지 않은 것은 구현해야합니다.
내가 지금 대답하는 것이 완전히 잘못되지 않았기를 바랍니다.
모두 좋은 하루 되세요!
[edit1] : 참고 : 이것은 Java 8에서만 작동합니다.
콜백 인터페이스를 구현하는 방법을 찾고 있었기 때문에 각 콜백에 대해 모든 메서드를 구현하고 싶지 않았기 때문에 선택적 메서드를 구현해야했습니다.
따라서 인터페이스를 사용하는 대신 다음과 같은 빈 구현이있는 클래스를 사용했습니다.
public class MyCallBack{
public void didResponseCameBack(String response){}
}
다음과 같이 멤버 변수 CallBack을 설정할 수 있습니다.
c.setCallBack(new MyCallBack() {
public void didResponseCameBack(String response) {
//your implementation here
}
});
이렇게 부르세요.
if(mMyCallBack != null) {
mMyCallBack.didResponseCameBack(response);
}
이렇게하면 콜백마다 모든 메서드를 구현하는 것에 대해 걱정할 필요가없고 필요한 메서드 만 재정의 할 수 있습니다.
OP의 질문에 답하지는 않지만 Java 8부터 인터페이스에 기본 메소드를 추가하는 것이 실제로 가능하다는 점에 주목할 가치가 있습니다. default
인터페이스의 메소드 서명에 배치 키워드는 메소드를 오버라이드 (override) 할 수있는 옵션을 가진 클래스 초래하지만, 그것을 필요로하지 않습니다.
관리 가능한 핵심 컬렉션 인터페이스 수를 유지하기 위해 Java 플랫폼은 각 컬렉션 유형의 각 변형에 대해 별도의 인터페이스를 제공하지 않습니다. (이러한 변형에는 불변, 고정 크기 및 추가 전용이 포함될 수 있습니다.) 대신 각 인터페이스의 수정 작업은 선택 사항으로 지정됩니다. 지정된 구현은 모든 작업을 지원하지 않도록 선택할 수 있습니다. 지원되지 않는 작업이 호출되면 컬렉션에서 UnsupportedOperationException을 throw합니다 . 구현은 지원하는 선택적 작업을 문서화해야합니다. 모든 Java 플랫폼의 범용 구현은 모든 선택적 작업을 지원합니다.