Phương thức triển khai “mặc định” được xác định trong Giao diện là gì?


91

Trong Giao diện Bộ sưu tập, tôi tìm thấy một phương thức được đặt tên removeIf()có chứa cách triển khai của nó.

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);  
    boolean removed = false;  
    final Iterator<E> each = iterator();   
    while (each.hasNext()) {  
        if (filter.test(each.next())) {  
            each.remove();  
            removed = true;  
        }  
    }  
    return removed;  
}  

Tôi muốn biết có cách nào để xác định thân phương thức trong giao diện không? Từ khóa
là gì defaultvà nó hoạt động như thế nào?



Câu trả lời:


162

Từ https://dzone.com/articles/interface-default-methods-java

Java 8 giới thiệu tính năng mới “Phương pháp mặc định” hoặc (Phương pháp của người bảo vệ), cho phép nhà phát triển thêm các phương thức mới vào giao diện mà không phá vỡ việc triển khai hiện có của giao diện này. Nó cung cấp tính linh hoạt để cho phép thực hiện xác định giao diện sẽ sử dụng làm mặc định trong trường hợp một lớp cụ thể không cung cấp triển khai cho phương thức đó.

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class ClassAB implements A {
}

Có một câu hỏi phổ biến mà mọi người hỏi về các phương pháp mặc định khi họ nghe về tính năng mới lần đầu tiên:

Điều gì sẽ xảy ra nếu lớp triển khai hai giao diện và cả hai giao diện đó xác định một phương thức mặc định với cùng một chữ ký?

Ví dụ minh họa tình huống này:

public interface A {  
    default void foo(){  
        System.out.println("Calling A.foo()");  
    }  
}

public interface B {
    default void foo(){
        System.out.println("Calling B.foo()");
    }
}


public class ClassAB implements A, B {

}  

Mã này không thể biên dịch với kết quả sau:

java: class Clazz inherits unrelated defaults for foo() from types A and B

Để khắc phục điều đó, trong Clazz, chúng tôi phải giải quyết nó theo cách thủ công bằng cách ghi đè phương thức xung đột:

public class Clazz implements A, B {
    public void foo(){}
}

Nhưng điều gì sẽ xảy ra nếu chúng ta muốn gọi việc triển khai mặc định của phương thức foo () từ giao diện A thay vì triển khai của riêng chúng ta.

Có thể tham chiếu đến A # foo () như sau:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}

18
Cảm ơn, giải trình thực sự tốt. Bạn đã trả lời tất cả các câu hỏi của tôi trước khi tôi có cơ hội hỏi chúng.
Jeff Hutchins

tại sao không sử dụng trừu tượng thay thế?
Astolfo Hoscher

1
@AstolfoHoscher Bạn chỉ có thể mở rộng một lớp, nhưng bạn có thể triển khai nhiều giao diện.
Charles Wood

49

Các phương thức đó được gọi là phương thức mặc định. Phương thức mặc định hoặc phương thức Defender là một trong những tính năng mới được bổ sung trong Java 8.

Chúng sẽ được sử dụng để cho phép một phương thức giao diện cung cấp một triển khai được sử dụng làm mặc định trong trường hợp một lớp cụ thể không cung cấp một triển khai cho phương thức đó.

Vì vậy, nếu bạn có một giao diện, với phương thức mặc định:

public interface Hello {
    default void sayHello() {
        System.out.println("Hello");
    }
}

Lớp sau hoàn toàn hợp lệ:

public class HelloImpl implements Hello {

}

Nếu bạn tạo một phiên bản của HelloImpl:

Hello hello = new HelloImpl();
hello.sayHello();  // This will invoke the default method in interface

Liên kết hữu ích:


Vì vậy, sẽ ổn nếu một lớp triển khai một giao diện và không triển khai phương thức của nó? Theo như Java7 có liên quan mà tôi đang sử dụng thì điều này không được phép.
Aniket Thakur

2
@AniketThakur. Điều này không được phép trước Java 8. Tính năng này chỉ được thêm vào Java 8. Bạn có thể tránh đưa ra việc triển khai các phương thức mặc định trong lớp thực thi của mình.
Rohit Jain

1
@PawanMishra. Xem bình luận trước của tôi. Không, bạn không cần cung cấp triển khai các phương thức giao diện mặc định trong việc triển khai lớp.
Rohit Jain

1
@PawanMishra bạn có thể ghi đè nó. Không có hạn chế chẳng hạn như bạn chỉ cần sử dụng triển khai mặc định.
Aniket Thakur

4
Một bước tiến cuối cùng sẽ tránh bị nhầm lẫn bởi đa thừa kế!
Xtreme Biker

17

Tôi đã thực hiện một chút nghiên cứu và tôi tìm thấy những điều sau đây. Hi vọng điêu nay co ich.

Vấn đề hiện tại

Các phương thức giao diện bình thường được khai báo là trừu tượng và phải được định nghĩa trong lớp thực thi giao diện. Điều này 'tạo gánh nặng' cho người triển khai lớp với trách nhiệm triển khai mọi phương thức đã khai báo. Quan trọng hơn, điều này cũng có nghĩa là không thể mở rộng giao diện sau khi 'xuất bản'. Nếu không, tất cả những người triển khai sẽ phải điều chỉnh việc triển khai của họ, phá vỡ khả năng tương thích nguồn và nhị phân ngược.

Giải pháp được thông qua trong Java 8

Để đối phó với những vấn đề này, một trong những tính năng mới của JDK 8 là khả năng mở rộng các giao diện hiện có với các phương thức mặc định. Các phương thức mặc định không chỉ được khai báo mà còn được định nghĩa trong giao diện.

Những điểm quan trọng cần lưu ý

  1. Người triển khai có thể chọn không triển khai các phương thức mặc định trong lớp thực thi.
  2. Người triển khai vẫn có thể ghi đè các phương thức mặc định, giống như các phương thức lớp không phải cuối cùng thông thường có thể bị ghi đè trong các lớp con.
  3. Các lớp trừu tượng thậm chí có thể (lại) khai báo các phương thức mặc định là trừu tượng, buộc các lớp con thực hiện lại phương thức (đôi khi được gọi là 'tái trừu tượng').
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.