2015-09-24 20 views
11

Tôi đang cố gắng viết một thư viện các giao diện bộ sưu tập thực hiện hầu hết các phương thức trong API thu thập tiêu chuẩn bằng cú pháp phương pháp mặc định mới trong Java 8. Đây là một ví dụ nhỏ về tôi sẽ cho:Lỗi Java 8: Giao diện thừa kế trừu tượng và mặc định

public interface MyCollection<E> extends Collection<E> { 
    @Override default boolean isEmpty() { 
     return !iterator().hasNext(); 
    } 
    //provide more default overrides below... 
} 

public interface MyList<E> extends MyCollection<E>, List<E> { 
    @Override default Iterator<E>iterator(){ 
     return listIterator(); 
    } 
    //provide more list-specific default overrides below... 
} 

Tuy nhiên, ngay cả ví dụ đơn giản này được đáp ứng với một lỗi biên dịch:

error: interface MyList<E> inherits abstract and default 
     for isEmpty() from types MyCollection and List 

Từ sự hiểu biết của tôi về phương pháp mặc định, điều này sẽ được phép vì chỉ có một trong những mở rộng giao diện cung cấp triển khai mặc định, nhưng ap không phải vậy. Những gì đang xảy ra ở đây? Có cách nào để có được điều này để làm những gì tôi muốn?

Trả lời

8

này được giải thích trong section 9.4.1.3 (Inheriting Methods with Override-Equivalent Signatures) của ngôn ngữ Java Specification:

It is possible for an interface to inherit several methods with override-equivalent signatures (§8.4.2).

...

Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).

Vì vậy, kể từ khi cả hai MyCollectionList xác định một phương pháp isEmpty() và một là mặc định và người kia là trừu tượng, trình biên dịch đòi hỏi subinterface tuyên bố một cách rõ ràng cái mà nó nên thừa hưởng bằng cách ghi đè phương thức một lần nữa. Nếu bạn muốn phương pháp mặc định của MyCollection được thừa hưởng, sau đó bạn có thể gọi nó trong việc thực hiện trọng:

public interface MyList<E> extends MyCollection<E>, List<E> { 
    @Override default boolean isEmpty() { 
     return MyCollection.super.isEmpty(); 
    } 

    @Override default Iterator<E> iterator(){ 
     return listIterator(); 
    } 
    ... 
} 

Nếu bạn muốn MyList để giữ isEmpty() trừu tượng (mà tôi không nghĩ rằng bạn muốn), bạn có thể làm:

public interface MyList<E> extends MyCollection<E>, List<E> { 
    @Override boolean isEmpty(); 

    @Override default Iterator<E> iterator(){ 
     return listIterator(); 
    } 
    ... 
} 
+0

Sự cần thiết phải sao chép tất cả các chữ ký phương pháp này là đáng thất vọng, nhưng điều này có vẻ giống như chính xác những gì tôi đang tìm kiếm. Được chấp nhận, giả sử không có cách nào để tránh điều này. –

+2

Điều thực sự xấu về nó là không có lý do cho 'List' để redeclare' isEmpty() '. Mục đích duy nhất có vẻ là thay đổi nhận xét tài liệu từ thừa kế "Trả về true nếu bộ sưu tập này không chứa các phần tử". Cụ thể hơn "Trả về true nếu danh sách này không chứa các phần tử." Không có điều này, mọi thứ sẽ hoạt động như trước nhưng biên dịch lỗi từ câu hỏi này sẽ được đi như 'MyCollection.isEmpty()' ghi đè 'Collection.isEmpty()' ... – Holger

+1

@ Holger Bạn đang phải trong trường hợp này. Nhưng đối với các phương thức khác như 'toArray', tài liệu khác nhiều hơn về hợp đồng phương thức. Tôi nghĩ rằng vấn đề này đến như là một mức giá để sử dụng các phương pháp mặc định. – manouti

0

thay đổi mã nguồn của bạn để

public interface MyList<E> extends MyCollection<E>,List<E> { 
    @Override 
    default boolean isEmpty(){ 
      return MyCollection.super.isEmpty(); 
     } 
} 

để biết thêm thông tin theo liên kết, default implementation in interface

+0

cuộc gọi đến 'MyCollection.super.isEmpty() 'là thừa –

+0

có !! sẽ cập nhật mã. – snAtchnAren

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