Java 8 인터페이스 메서드에서 "최종"이 허용되지 않는 이유는?
Java 8의 가장 유용한 기능 중 하나는 새로운 것이다.default
인터페이스의 방법그들이 소개된 이유는 본질적으로 두 가지(다른 이유가 있을 수 있음)가 있다.
- 실제 기본 구현 제공.예:
- JDK API의 진화 허용.예:
API 디자이너의 입장에서 볼 때 인터페이스 방법 등에 다른 수식어를 사용할 수 있었으면 좋았을 것이다.final
. 이는 클래스 구현 시 "우발적인" 오버라이드를 방지하여 편의 방법을 추가할 때 유용할 수 있다.
interface Sender {
// Convenience method to send an empty message
default final void send() {
send(null);
}
// Implementations should only implement this method
void send(String message);
}
위와 같은 것은 다음과 같은 경우에 이미 일반적인 관행은 다음과 같다.Sender
수업시간:
abstract class Sender {
// Convenience method to send an empty message
final void send() {
send(null);
}
// Implementations should only implement this method
abstract void send(String message);
}
지금default
그리고final
분명히 키워드를 반박하는 것이지만 기본 키워드 자체는 엄격하게 요구되지 않았을 것이므로, 이 모순은 '몸과 함께 하는 클래스 메서드'(정당한 방법)와 '몸과 인터페이스 메서드'(기본 방법)의 미묘한 차이, 즉 내가 아직 이해하지 못한 차이점을 반영하기 위해 의도적인 것이라고 추측하고 있다.
어느 시점에서는 다음과 같은 수식어를 지원한다.static
그리고final
브라이언 괴츠를 인용하여 인터페이스 방법은 아직 완전히 탐구되지 않았다.
다른 부분은 최종 방법, 비공개 방법, 보호 방법, 정적 방법 등 인터페이스에서의 클래스 구축 도구를 지원하기 위해 어디까지 갈 것인가 입니다.답은: 우리는 아직 모른다.
2011년 말 그 시기 이후, 분명히, 에 대한 지원.static
인터페이스의 메서드가 추가되었다.분명히, 이것은 와 같은 JDK 라이브러리 자체에 많은 가치를 더했다.
질문:.
그 이유는 무엇인가?final
(또한)static final
)은(는) Java 8 인터페이스에 도달하지 못했는가?
이 질문은 어느 정도 Java 8 인터페이스 방법에서 "동기화"가 허용되지 않는 이유는 무엇인가?
디폴트 방법에 대해 이해해야 할 핵심 사항은 주된 설계 목표가 "인터페이스의 특성을 (중간) 특성으로 바꾸는 것"이 아니라 인터페이스 진화라는 점이다.두 가지 사이에 어느 정도 겹치는 부분이 있고, 전자에 방해가 되지 않는 후자를 수용하려고 노력했지만, 이러한 질문들은 이러한 관점에서 볼 때 가장 잘 이해된다.(참고 역시 클래스 방식은 인터페이스 방식이란 사실 때문에 의도성이 어떻든 인터페이스 방식과 다를 것이다.s는 유전될 수 있다.)
디폴트 방법의 기본 개념은 디폴트 구현이 가능한 인터페이스 방법이며, 파생 클래스는 보다 구체적인 구현을 제공할 수 있다.그리고 설계 센터가 인터페이스 진화였기 때문에, 소스 호환 및 이진 호환 방식으로 사실 다음에 인터페이스에 기본 방법을 추가할 수 있다는 것은 중요한 설계 목표였다.
"최종 디폴트 방법이 아닌 이유"에 대한 너무 단순한 대답은, 그러면 기구가 단순히 디폴트 구현이 아니라, 유일한 구현이 된다는 것이다.그것이 너무 간단한 대답이지만, 그것은 우리에게 그 질문이 이미 의문스러운 방향으로 향하고 있다는 단서를 준다.
최종 인터페이스 방식이 의문스러운 또 다른 이유는 구현자에게 불가능한 문제를 야기하기 때문이다.예를 들어 다음과 같이 가정해 보십시오.
interface A {
default void foo() { ... }
}
interface B {
}
class C implements A, B {
}
여기선 모든 것이 좋다.C
상속하다foo()
로부터A
. 지금으로 미루어 본다면B
A을 갖는 것으로 바뀌다.foo
메서드(기본값 포함):
interface B {
default void foo() { ... }
}
자, 우리가 다시 컴파일하러 갈 때C
컴파일러는 우리에게 어떤 행동을 이어받아야 할지 모른다고 말할 것이다.foo()
그렇게C
(그리고 위임하는 것을 선택할 수 있다)A.super.foo()
같은 행동을 유지하기를 원한다면)하지만 만약B
채무 불이행을 했었었다.final
그리고A
의 저자의 지배하에 있지 않다.C
?이제C
되돌릴 수 없을 정도로 부서진 상태여서, 재정의하지 않고는 컴파일할 수 없다.foo()
, 그러나 무시할 수 없다.foo()
마지막이라면B
.
이것은 하나의 예에 불과하지만, 요점은 방법에 대한 최종성은 단순히 행동에 기여하고 유전될 수 있는 인터페이스보다는 단일 상속계급(일반적으로 행동에 대한 커플링)의 세계에서 더 이치에 맞는 도구라는 것이다."다른 인터페이스가 최종 구현자에 섞일 수 있는 것"에 대해 추론하는 것은 너무 어렵고, 인터페이스 방법을 최종으로 허용하는 것은 이러한 문제를 야기할 가능성이 높다(그리고 인터페이스를 작성한 사람이 아니라 그것을 구현하려고 하는 가난한 사용자에게 폭발할 것이다).
그들을 허락하지 않는 또 다른 이유는 그들이 당신이 생각하는 의미에 대해 의미하지 않기 때문이다.디폴트 이행은 계층(또는 그 슈퍼클래스)이 방법에 대한 선언(구체적 또는 추상적)을 제공하지 않는 경우에만 고려된다.디폴트 메서드가 최종적이었지만 슈퍼클래스가 이미 메서드를 구현했다면 디폴트(default)는 무시될 것이며 이는 디폴트(default) 작성자가 최종으로 선언할 때 예상한 바는 아닐 것이다.(이 상속 행위는 기본 방법인 인터페이스 진화에 대한 디자인 센터의 반영이다.인터페이스를 구현하는 기존 클래스의 동작을 변경하지 않고 이미 구현된 기존 인터페이스에 기본 방식(또는 기존 인터페이스 방식에 기본 구현)을 추가할 수 있어야 하며, 기본 방식이 추가되기 전에 이미 작동한 클래스가 동일한 방식으로 작동하도록 보장해야 한다.디폴트 메서드(default methods.
람다 메일링 리스트에는 그것에 대한 많은 토론이 있다.그 모든 것에 대해 많은 논의를 담고 있는 것으로 보이는 것 중 하나는 다음과 같다.다양한 인터페이스 방법 가시성(Final Defender 포함)
이 토론에서 원문의 저자 탈든은 당신의 질문과 매우 유사한 것을 질문한다.
모든 인터페이스 멤버를 공개하기로 한 결정은 정말 불행한 결정이었다.내부 설계에서 인터페이스의 어떠한 사용도 구현의 사적인 세부사항을 노출한다는 것은 큰 일이다.
언어에 모호하거나 양립성을 깨는 뉘앙스를 첨가하지 않고서는 고치기 힘들다.그 규모와 잠재적인 미묘함의 호환성 파괴는 비양심적인 것으로 보일 수 있기 때문에 기존 코드를 파괴하지 않는 해결책이 존재해야 한다.
액세스 지정자로 '패키지' 키워드를 다시 도입할 수 있다.인터페이스에 지정자가 없다는 것은 공공 액세스를 의미할 수 있고 클래스에 지정자가 없다는 것은 패키지 액세스를 의미한다.인터페이스에서 어떤 지정자가 이치에 맞는지는 불분명하다. 특히 개발자의 지식 부담을 최소화하기 위해, 접속 지정자가 존재하는 경우, 우리는 접속 지정자가 클래스와 인터페이스 모두에서 동일한 것을 의미하는지 확인해야 한다.
디폴트 메소드가 없는 상황에서 나는 인터페이스의 멤버 지정자가 적어도 인터페이스 자체만큼 가시적이어야 한다고 추측했다(그래서 인터페이스가 실제로 모든 가시적 컨텍스트에서 구현될 수 있다). - 그렇게 확실하지 않은 디폴트 메소드가 있는 것이다.
이것이 심지어 가능한 범위 내 논의인지에 대해 명확한 의사소통이 있었는가?그렇지 않다면 다른 곳에서 개최해야 한다.
결국 브라이언 괴츠의 대답은 다음과 같았다.
네, 이것은 이미 탐구되고 있다.
하지만 현실적인 기대치를 설정해 봅시다. 언어/VM 기능에는 리드 타임이 길고, 심지어 이와 같은 사소한 기능도 포함된다.자바 SE 8을 위한 새로운 언어 특징 아이디어를 제안할 시간이 꽤 지났다.
그래서, 그것은 결코 범위에 포함되지 않았기 때문에 실행되지 않았을 가능성이 크다.그것은 고려되어야 할 시기에 제안된 적이 없다.
이 주제에 대한 최종 수비수 방법에 대한 또 다른 열띤 토론에서 브라이언은 다시 이렇게 말했다.
그리고 당신은 당신이 원하는 것을 정확히 얻었다.이것이 바로 이 기능이 덧붙인 것이 바로 행동의 다중 상속이다.물론 우리는 사람들이 그것들을 특성으로 사용할 것이라는 것을 이해한다.그리고 우리는 그들이 제공하는 상속 모델이 간단하고 깨끗해서 사람들이 다양한 상황에서 좋은 결과를 얻을 수 있도록 하기 위해 열심히 노력해왔다.우리는 동시에 단순하고 깨끗하게 작용하는 것의 경계를 넘어 그들을 밀어내지 않기로 선택했고, 그것은 어떤 경우에는 "아, 너는 충분히 멀리 가지 않았구나"라는 반응을 이끌어냈다.하지만 사실, 이 실의 대부분은 유리가 98%밖에 채워지지 않았다고 불평하는 것 같다.98%로 잡고 계속 해나가야겠어!
그래서 이것은 그것이 단순히 그들의 설계의 범위나 일부가 아니라는 나의 이론을 강화시킨다.그들이 한 일은 API 진화의 문제를 다루기에 충분한 기능을 제공하는 것이었습니다.
@EJP의 논평에서 언급된 레슨들 때문에, "THE"의 답을 찾고 식별하기는 어려울 것이다. 이 세상에는 확답을 줄 수 있는 사람이 대략 2명(+/- 2)이나 있다.그리고 의심스러운 것은 "최종 채무불이행 방법을 지원하는 것이 내부 통화 해결 메커니즘을 재구성하는 노력의 가치가 없어 보였다"와 같은 것일 수도 있다.물론 이것은 추측이지만, 최소한 OpenJDK 메일링 리스트에 있는 (두 사람 중 한 사람)과 같은 미묘한 증거에 의해 뒷받침된다.
"최종 기본" 방법이 허용되었다면 사용자가 볼 수 있는 호출인터페이스에 대해 특별히 내부 호출에서 다시 써야 할지도 모른다"고 말했다.
그리고 그와 같은 사소한 사실들은 단순히 그것이 (진짜) 최종적인 방법일 때 고려되지 않는다.default
방법(현재 OpenJDK의 Method:is_final_method 방법)에서 구현된 방법.
웹 검색이 과도하고 로그를 읽어도 실제로 "권위적인" 정보는 찾기 어렵다.인터페이스 방식 호출을 해결하는 과정에서 잠재적 모호성과 관련이 있을 수 있다고 생각했다.invokeinterface
instruction and and class method calls, corresponding to the invokevirtual
instruction: For the invokevirtual
instruction, there may be a simple vtable lookup, because the method must either be inherited from a superclass, or implemented by the class directly. In contrast to that, an invokeinterface
call must examine the respective call site to find out which interface this call actually refers to (this is explained in more detail in the InterfaceCalls page of the HotSpot Wiki). However, final
methods do either not get inserted into the vtable at all, or replace existing entries in the vtable (see klassVtable.cpp. Line 333), and similarly, default methods are replacing existing entries in the vtable (see klassVtable.cpp, Line 202). So the actual reason (and thus, the answer) must be hidden deeper inside the (rather complex) method call resolution mechanisms, but maybe these references will nevertheless be considered as being helpful, be it only for others that manage to derive the actual answer from that.
I wouldn't think it is neccessary to specify final
on a convienience interface method, I can agree though that it may be helpful, but seemingly the costs have outweight the benefits.
What you are supposed to do, either way, is to write proper javadoc for the default method, showing exactly what the method is and is not allowed to do. In that way the classes implementing the interface "are not allowed" to change the implementation, though there are no guarantees.
Anyone could write a Collection
that adheres to the interface and then does things in the methods that are absolutely counter intuitive, there is no way to shield yourself from that, other than writing extensive unit tests.
We add default
keyword to our method inside an interface
when we know that the class extending the interface
may or may not override
our implementation. But what if we want to add a method that we don't want any implementing class to override? Well, two options were available to us:
- Add a
default
final
method. - Add a
static
method.
Now, Java says that if we have a class
implementing two or more interfaces
such that they have a default
방법 이름과 서명이 정확히 동일한 방법, 즉 중복된 방법, 그러면 우리는 우리 반에서 그 방법의 구현을 제공해야 한다.이제 만약의 경우에는default
final
방법들, 우리는 구현을 제공할 수 없고 우리는 막혀있다.그래서인지final
키워드가 인터페이스에서 사용되지 않음.
참조URL: https://stackoverflow.com/questions/23453287/why-is-final-not-allowed-in-java-8-interface-methods
'Programing' 카테고리의 다른 글
충돌 @Dragenter @Dragleave / v-show 이벤트가 계속 빠르게 발생함 (0) | 2022.05.09 |
---|---|
IntelliJ IDEA 13은 1.7로 설정되었음에도 불구하고 Java 1.5를 사용한다. (0) | 2022.05.09 |
(A + B + C) ≠ (A + C + B) 및 컴파일러 재주문 (0) | 2022.05.08 |
1D 또는 2D 어레이, 어떤 것이 더 빠른가? (0) | 2022.05.08 |
정의되지 않은 VUEX의 '커밋' 속성을 읽을 수 없음 (0) | 2022.05.08 |