2015-04-08 25 views
24

Giả sử có hai giao diện Interface1Interface2 trong đó Interface2 mở rộng Interface1.Các phương thức và giao diện mặc định mở rộng các giao diện khác

interface Interface1 { 

    default void method() { 
     System.out.println("1"); 
    } 

    // Other methods 
} 

interface Interface2 extends Interface1 { 

    @Override 
    default void method() { 
     System.out.println("2"); 
    } 

    // Other methods 
} 

Giả sử tôi muốn tạo ra một lớp mà thực hiện Interface2 nhưng tôi muốn method() là phiên bản trong Interface1. Nếu tôi viết

class MyClass implements Interface1, Interface2 { 

    public void method() { 
     Interface1.super.method(); 
    } 
} 

tôi nhận được lỗi biên dịch:

bad type qualifier in default super call: redundant interface Interface1 is extended by Interface2

Có thể làm được việc này bằng cách tạo ra một giao diện thứ ba:

interface Interface3 extends Interface1 { 

    default void method() { 
     Interface1.super.method(); 
    } 
} 

Sau đó:

class MyClass implements Interface1, Interface2, Interface3 { 

    public void method() { 
     Interface3.super.method(); 
    } 
} 

Việc biên dịch này tốt và nếu tôi tham gia stantiate một MyClass mới và gọi method(), đầu ra là 1 như mong đợi. Vì vậy, câu hỏi của tôi là, cho rằng nó là như vậy dễ dàng để có được xung quanh hạn chế mà bạn chỉ có thể viết InterfaceName.super.method() cho giao diện cụ thể nhất trong một chuỗi, lý do cho việc hạn chế là những gì ?. Những vấn đề gì được ngăn cản bằng cách không cho phép bạn viết Interface1.super.method() ngay từ đầu?

+2

Nếu 'Interface2 kéo dài Interface1', trong đó kịch bản bạn muốn có một lớp để thực hiện chúng * cả *? – Maroun

+0

@MarounMaroun Bạn nói đúng, không có điểm nào viết cả hai. Nó chỉ là trên IntelliJ tôi nhận được một thông báo lỗi ít hữu ích nếu tôi chỉ viết 'Interface2'. –

+0

các phương thức trong 'giao diện' có phần thân, đoán tôi phải sửa lại những điều cơ bản của mình. Tôi nghĩ rằng họ được cho là trừu tượng –

Trả lời

16

Điều này được giải quyết chính xác bằng JLS trong 15.12.3."Thời gian biên dịch Bước 3: Phương pháp được chọn có phù hợp không?".

If the form is TypeName . super . [TypeArguments] Identifier, then:

  • […]
  • If TypeName denotes an interface, let T be the type declaration immediately enclosing the method invocation. A compile-time error occurs if there exists a method, distinct from the compile-time declaration, that overrides (§9.4.1) the compile-time declaration from a direct superclass or direct superinterface of T .

Các JLS tiếp tục giải thích lý do tại sao các quy tắc được đặt ra:

In the case that a superinterface overrides a method declared in a grandparent interface, this rule prevents the child interface from "skipping" the override by simply adding the grandparent to its list of direct superinterfaces. The appropriate way to access functionality of a grandparent is through the direct superinterface, and only if that interface chooses to expose the desired behavior.

Vì vậy, nó ít nhiều tồn tại đặc biệt để ngăn chặn bạn làm những gì bạn đang cố gắng làm.

Nhưng JLS cũng dường như thừa nhận cách giải quyết của bạn:

(Alternately, the developer is free to define his own additional superinterface that exposes the desired behavior with a super method invocation.)

+0

Điều đó thực sự thú vị. Họ ổn với workaraound (mà có vẻ như là một hack với tôi), nhưng lý do duy nhất họ đã không cho phép bản gốc là họ không coi nó là "thích hợp". –

+1

Vâng, có vẻ hơi lạ. Có lẽ @BrianGoetz (hi Brian) có một số nhận xét về lý do. – Radiodef

+1

Vâng, tôi cũng thấy điều đó thật kỳ lạ. Tôi sẽ hiểu nếu, ví dụ, javadoc tự động phát hiện việc triển khai thực hiện mà lớp con chọn để sử dụng và tạo ra tài liệu thích hợp. Nhưng tôi nghi ngờ đó là trường hợp, vì, AFAIK, javadoc không quan tâm đến cơ thể của phương pháp. –

Các vấn đề liên quan