Mục đích của từ khóa mặc định trong Java là gì?


94

Giao diện trong Java tương tự như một lớp, nhưng phần thân của giao diện chỉ có thể bao gồm các phương thứcfinaltrường trừu tượng (hằng số).

Gần đây, tôi thấy một câu hỏi, có dạng như sau

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

Theo định nghĩa giao diện, chỉ cho phép các phương thức trừu tượng . Tại sao nó cho phép tôi biên dịch đoạn mã trên? Là gì defaulttừ khoá?

Mặt khác, khi tôi cố gắng viết mã bên dưới, thì nó nói modifier default not allowed here

default class MyClass{

}

thay vì

class MyClass {

}

Bất cứ ai có thể cho tôi biết mục đích của defaulttừ khóa? Nó chỉ được phép bên trong một giao diện? Nó khác với default(không có công cụ sửa đổi truy cập) như thế nào?


4
các phương thức mặc định trong giao diện đã được thêm vào trong Java 8. Nó không phải là một công cụ sửa đổi quyền truy cập, nó là một triển khai mặc định.
Eran

2
@Eran, bạn có nghĩ vậy không, việc giới thiệu phương thức mặc định vi phạm định nghĩa giao diện? : s
Ravi

2
Nó đã thay đổi định nghĩa giao diện. Định nghĩa đó hiện đã lỗi thời.
Louis Wasserman

2
Họ đã được giới thiệu để hỗ trợ lambdas. Chi tiết về lý do tại sao chúng được yêu cầu có trong đề xuất người lái rơm cho Dự án Lambda.
vận động viên chạy nước rút,

Câu trả lời:


74

Đó là một tính năng mới trong Java 8 cho phép một interfacecung cấp một triển khai. Được mô tả trong Java 8 JLS-13.5.6. Khai báo phương thức giao diện đọc (một phần)

Việc thêm một defaultphương thức hoặc thay đổi một phương thức từ abstractthành defaultkhông phá vỡ khả năng tương thích với các mã nhị phân đã có từ trước, nhưng có thể gây ra lỗi IncompatibleClassChangeErrornếu một nhị phân tồn tại trước đó cố gắng gọi phương thức. Lỗi này xảy ra nếu kiểu đủ điều kiện T, là kiểu con của hai giao diện IJ, trong đó cả hai IJkhai báo một defaultphương thức với cùng một chữ ký và kết quả, và không Iphải Jlà giao diện con của phương thức kia.

Có gì mới trong JDK 8 nói (một phần)

Các phương thức mặc định cho phép thêm chức năng mới vào giao diện của các thư viện và đảm bảo tính tương thích nhị phân với mã được viết cho các phiên bản cũ hơn của các giao diện đó.


16
Có vẻ như bây giờ giao diện và lớp trừu tượng gần như giống nhau. :)
Ravi

16
Các giao diện @jWeaver vẫn không thể có hàm tạo, trường, phương thức riêng tư hoặc triển khai bằng / hashCode / toString.
Louis Wasserman,

10
@Louis Wasserman: Trong Java 9, chúng có thể có privatecác phương thức.
Holger

6
@Dan Pantry: privatecác phương thức không thực sự là một phần của giao diện, nhưng có thể đóng vai trò là phương thức trợ giúp cho việc defaulttriển khai hoặc trong các trình khởi tạo không đổi. Lưu ý rằng chúng đã tồn tại trong Java 8, vì khi bạn sử dụng biểu thức lambda trong các giao diện, privatecác phương thức tổng hợp sẽ được tạo ra. Vì vậy, Java 9 cho phép bạn sử dụng tính năng đó cho người không tổng hợp, sử dụng phi lambda cũng ...
Holger

14
@jWeaver Sự khác biệt giữa giao diện và lớp giảm xuống trạng thái so với hành vi . Các giao diện có thể mang hành vi, nhưng chỉ các lớp mới có thể có trạng thái. (Fields, nhà thầu, và các phương pháp như bình đẳng / hashCode là về tình trạng.)
Brian Goetz

26

Các phương thức mặc định đã được thêm vào Java 8 chủ yếu để hỗ trợ các biểu thức lambda. Các nhà thiết kế (theo quan điểm của tôi một cách thông minh) đã quyết định tạo cú pháp lambdas để tạo ra các triển khai ẩn danh của một giao diện. Nhưng các lambdas đưa ra chỉ có thể triển khai một phương pháp duy nhất, chúng sẽ bị giới hạn ở các giao diện với một phương thức duy nhất, đây sẽ là một hạn chế khá nghiêm trọng. Thay vào đó, các phương thức mặc định đã được thêm vào để cho phép sử dụng các giao diện phức tạp hơn.

Nếu bạn cần một số thuyết phục về tuyên bố defaultđã được đưa ra do lambdas, hãy lưu ý rằng đề xuất người rơm của Dự án Lambda, của Mark Reinhold, vào năm 2009, đề cập đến 'Các phương pháp mở rộng' như một tính năng bắt buộc phải được thêm vào để hỗ trợ lambdas.

Đây là một ví dụ minh họa khái niệm:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

Tôi nhận ra rất giả tạo nhưng nên minh họa cách defaulthỗ trợ lambdas. Vì inverselà mặc định nên nó có thể dễ dàng bị ghi đè bởi một lớp thực thi nếu được yêu cầu.


8
Điều này không thực sự chính xác. Lambdas có thể là nguyên nhân gần nhất, nhưng chúng thực sự chỉ là rơm làm gãy lưng lạc đà. Động lực thực sự là cho phép phát triển giao diện (cho phép các giao diện hiện có được phát triển một cách tương thích để hỗ trợ hành vi mới); lambdas có thể là yếu tố đưa nhu cầu này lên hàng đầu, nhưng tính năng này tổng quát hơn thế.
Brian Goetz

@BrianGoetz: IMHO, cả Java và .NET sẽ được hưởng lợi rất nhiều nếu các phương thức mặc định tồn tại ngay từ đầu. Nếu một số hoạt động phổ biến có thể được thực hiện trên bất kỳ triển khai nào của giao diện chỉ sử dụng các thành viên giao diện, nhưng một số triển khai có thể có cách thực hiện hiệu quả hơn, giao diện phải xác định các phương thức cho các hoạt động đó và cung cấp các triển khai mặc định cho chúng. Việc không thể chỉ định các triển khai mặc định đã gây ra áp lực buộc các giao diện phải bỏ qua các phương thức như vậy và khiến họ không thể thêm chúng sau này.
supercat

@BrianGoetz Tôi đồng ý rằng các phương thức mặc định có giá trị đáng kể ngoài lambdas. Nhưng tôi quan tâm đến bất kỳ tài liệu tham khảo nào mà bạn có thể cung cấp cho giá trị rộng hơn đó dẫn đến quyết định bao gồm chúng. Bài đọc của tôi cho rằng lambdas là lý do chính (đó là lý do tại sao tôi sử dụng từ 'chủ yếu' trong câu trả lời của mình).
vận động viên chạy nước rút

2
Có lẽ tài liệu này sẽ hữu ích: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html . Phần 10 nói rõ ràng: "Mục đích của các phương thức mặc định (trước đây được gọi là phương pháp mở rộng ảo hoặc phương thức bảo vệ) là cho phép các giao diện được phát triển theo cách tương thích sau khi xuất bản lần đầu." Các phương pháp thân thiện với Lambda sau đó được trích dẫn như một minh họa cho sự phát triển giao diện.
Brian Goetz

2
@Kartik Bạn đang đặt câu hỏi sai! Chúng tôi không chọn cú pháp dựa trên "mức tối thiểu tuyệt đối cần thiết để trình biên dịch phân tích cú pháp chương trình một cách chính xác"; chúng tôi chọn nó trên cơ sở "điều gì sẽ làm cho ý định của lập trình viên trở nên rõ ràng hơn ngay lập tức cho người đọc." Chúng tôi thiết kế đầu tiên cho người dùng, và secondarily cho trình biên dịch (và khi nói đến người dùng, chúng tôi thiết kế đầu tiên cho việc đọc, và secondarily cho văn bản.)
Brian Goetz

16

Một khái niệm mới được giới thiệu trong Java 8 được gọi là phương thức mặc định. Phương thức mặc định là những phương thức có một số triển khai mặc định và giúp phát triển các giao diện mà không phá vỡ mã hiện có. Hãy xem một ví dụ:

 public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

 class SimpleInterfaceImpl implements SimpleInterface{

  @Override
  public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Not required to override to provide an implementation
  * for doSomeOtherWork.
  */

 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

và đầu ra là:

Thực hiện một số công việc triển khai trong lớp
DoSomeOtherWork triển khai trong giao diện


16

Một cái gì đó đã bị bỏ qua trong các câu trả lời khác là vai trò của nó trong các chú thích. Đối với Java 1.5, defaulttừ khóa đã xuất hiện như một phương tiện để cung cấp giá trị mặc định cho trường chú thích.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

Việc sử dụng nó đã bị quá tải với sự ra đời của Java 8 để cho phép người ta xác định một phương thức mặc định trong các giao diện.

Một cái gì đó khác đã bị bỏ qua: lý do mà khai báo default class MyClass {}không hợp lệ là do cách mà các lớp được khai báo . Không có điều khoản nào trong ngôn ngữ cho phép từ khóa đó xuất hiện ở đó. Tuy nhiên, xuất hiện cho các khai báo phương thức giao diện .


3

Mới Java 8 tính năng ( Mặc định phương pháp ) cho phép một giao diện để cung cấp một thực hiện khi dán nhãn của nó với các defaulttừ khóa.

Ví dụ:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

Kiểm tra giao diện sử dụng từ khóa mặc định cho phép giao diện cung cấp triển khai mặc định của phương thức mà không cần triển khai các phương thức đó trong các lớp sử dụng giao diện.

Tương thích ngược: Hãy tưởng tượng rằng giao diện của bạn được thực hiện bởi hàng trăm lớp, việc sửa đổi giao diện đó sẽ buộc tất cả người dùng phải triển khai phương thức mới được thêm vào, mặc dù nó không cần thiết cho nhiều lớp khác triển khai giao diện của bạn.

Sự thật & Hạn chế:

1-Chỉ có thể được khai báo trong một giao diện chứ không phải trong một lớp hoặc lớp trừu tượng.

2-Phải cung cấp một cơ thể

3-Nó không được giả định là công khai hoặc trừu tượng như các phương thức bình thường khác được sử dụng trong một giao diện.


3

Các phương thức mặc định trong giao diện cho phép chúng tôi thêm chức năng mới mà không phá vỡ mã cũ.

Trước Java 8, nếu một phương thức mới được thêm vào một giao diện, thì tất cả các lớp triển khai của giao diện đó bị ràng buộc ghi đè phương thức mới đó, ngay cả khi chúng không sử dụng chức năng mới.

Với Java 8, chúng ta có thể thêm cài đặt mặc định cho phương thức mới bằng cách sử dụng defaulttừ khóa trước khi triển khai phương thức.

Ngay cả với các lớp ẩn danh hoặc giao diện chức năng, nếu chúng ta thấy rằng một số mã có thể sử dụng lại và chúng ta không muốn xác định cùng một logic ở mọi nơi trong mã, chúng ta có thể viết các triển khai mặc định của chúng và sử dụng lại chúng.

Thí dụ

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

2

Một lời giải thích rất hay được tìm thấy trong Hướng dẫn Java ™ , một phần của lời giải thích như sau:

Hãy xem xét một ví dụ liên quan đến các nhà sản xuất ô tô điều khiển bằng máy tính xuất bản các giao diện tiêu chuẩn công nghiệp mô tả phương pháp nào có thể được sử dụng để vận hành ô tô của họ. Điều gì sẽ xảy ra nếu những nhà sản xuất ô tô được điều khiển bằng máy tính đó thêm chức năng mới, chẳng hạn như chuyến bay, vào ô tô của họ? Các nhà sản xuất này sẽ cần chỉ định các phương pháp mới để cho phép các công ty khác (chẳng hạn như các nhà sản xuất thiết bị hướng dẫn điện tử) điều chỉnh phần mềm của họ cho ô tô bay. Các nhà sản xuất ô tô sẽ khai báo các phương pháp liên quan đến chuyến bay mới này ở đâu? Nếu họ thêm chúng vào giao diện ban đầu của họ, thì các lập trình viên đã triển khai các giao diện đó sẽ phải viết lại các triển khai của họ. Nếu họ thêm chúng dưới dạng phương thức tĩnh, thì các lập trình viên sẽ coi chúng là phương thức tiện ích, không phải là phương thức cốt lõi, thiết yếu.

Các phương pháp mặc định cho phép bạn thêm chức năng mới vào giao diện của thư viện và đảm bảo tính tương thích nhị phân với mã được viết cho các phiên bản cũ hơn của các giao diện đó.


1

Các phương pháp mặc định cho phép bạn thêm chức năng mới vào giao diện ứng dụng của mình. Nó cũng có thể được sử dụng để có đa thừa kế . Ngoài các phương thức mặc định, bạn có thể xác định các phương thức tĩnh trong giao diện. Điều này giúp bạn tổ chức các phương thức trợ giúp dễ dàng hơn

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.