Các giá trị mặc định trong JDK 8 có phải là một dạng đa kế thừa trong Java không?


83

Một tính năng mới sắp có trong JDK 8 cho phép bạn thêm vào giao diện hiện có mà vẫn duy trì khả năng tương thích nhị phân.

Cú pháp giống như

public interface SomeInterface() {
  void existingInterface();
  void newInterface() default SomeClass.defaultImplementation;
}

Bằng cách này cho tất cả các triển khai hiện có SomeInterfacekhi họ nâng cấp lên phiên bản mới này, chúng không đột nhiên có lỗi biên dịch xung quanh newInterface().

Mặc dù điều này rất gọn gàng, nhưng điều gì sẽ xảy ra khi bạn đang triển khai hai giao diện mà cả hai đều đã thêm một phương thức mặc định mới mà bạn không triển khai? Hãy để tôi giải thích bằng một ví dụ.

public interface Attendance {
   boolean present() default DefaultAttendance.present;
}

public interface Timeline {
   boolean present() default DefaultTimeline.present;
}

public class TimeTravelingStudent implements Attendance, Timeline {

}

// which code gets called?
new TimeTravelingStudent().present();

Điều này đã được xác định là một phần của JDK 8 chưa?

Tôi thấy các vị thần Java đang nói về điều gì đó tương tự ở đây http://cs.oswego.edu/pipermail/lambda-lib/2011-Feb 02/000068.html , nhưng nó là một phần của danh sách gửi thư riêng và tôi không thể hỏi họ trực tiếp.

Xem phần này để biết thêm chi tiết về cách các mặc định sẽ được sử dụng trong JDK 8 và mở rộng giao diện Bộ sưu tập để hỗ trợ lambdas: https://oracleus.wingateweb.com/published/oracleus2011/sessions/25066/25066_Cho223662.pdf


Phiên video để xem ở đây medianetwork.oracle.com/video/player/1113272518001 Đây là nhà thiết kế nói về tính năng được gọi là Virtual Extensions. Anh ấy cũng nói về cách điều này không phá vỡ khả năng tương thích ngược.
Peter Lawrey

Vì vậy, câu trả lời cho ví dụ của tôi là hiện tại bạn gặp lỗi trình biên dịch. Nhưng họ đang mở cho các giải pháp khác.
Pyrolistical

Một tài liệu hữu ích khác cho việc này là cr.openjdk.java.net/~briangoetz/lambda/…
MohamedSanaulla Ngày

Sidenote: cú pháp cuối cùng cho việc triển khai mặc định của các phương thức giao diện hóa ra lại khác (khối mã thay vì tham chiếu đến một lớp bên ngoài).
Joachim Sauer

4
Java luôn có kế thừa của nhiều loại . Các phương thức mặc định bổ sung nhiều thừa kế của hành vi , nhưng không bổ sung trạng thái . (Nhiều thừa kế của nhà nước trong các ngôn ngữ như C ++ là nơi mà hầu hết những rắc rối đến từ đâu.)
Brian Goetz

Câu trả lời:


66

Câu trả lời cho hoạt động trùng lặp là:

Để giải quyết vấn đề đa kế thừa, một lớp thực hiện hai giao diện cung cấp một triển khai mặc định cho cùng một tên phương thức và chữ ký phải cung cấp một triển khai của phương thức. [Bài báo đầy đủ]

Câu trả lời của tôi cho câu hỏi của bạn là: Có, đó là một dạng đa thừa kế, vì bạn có thể thừa kế hành vi từ các bậc cha mẹ khác nhau. Điều còn thiếu là kế thừa các trạng thái, tức là các thuộc tính.


2
+1: Khi có xung đột, nó sẽ thực hiện một cách cụ thể hơn so với một triển khai ít cụ thể hơn, cho phép bạn chỉ định nó nên được triển khai nếu có xung đột.
Peter Lawrey

@ H-Man2 Tôi không hiểu. Nếu điều đó là đúng, nó có nghĩa là nó sẽ phá vỡ khả năng tương thích nhị phân. Bây giờ có lẽ điều đó không quá tệ khi phá vỡ khả năng tương thích nhị phân để ngăn đa thừa kế, phá vỡ khả năng tương thích nhị phân.
Pyrolistical

@PeterLawrey cái nào cụ thể hơn trong ví dụ của tôi?
Pyrolistical

@Pyrolistical: Không, nó không phá vỡ khả năng tương thích, bởi vì trình biên dịch có thể dịch việc triển khai mặc định thành một cuộc gọi phương thức bình thường. Tôi nghĩ rằng nó là một macro kế thừa thực sự, nhưng có thể mô phỏng các khía cạnh của đa kế thừa. Có thể video từ Peter cung cấp câu trả lời chi tiết hơn.
H-Man2

thực ra chúng tôi có thể khắc phục các bang mất tích bằng cách thu khí trừu tượng và setters, lớp thực hiện có thể thêm các bang ...
vikkyhacks

8

Tôi biết đây là một bài viết cũ, nhưng vì tôi đang làm việc với thứ này ...

Bạn sẽ gặp lỗi từ trình biên dịch, cho bạn biết rằng:

 class TimeTravelingStudent kế thừa các giá trị mặc định không liên quan cho hiện tại () từ các kiểu Tham dự và Dòng thời gian tham chiếu đến hiện tại là không rõ ràng, cả phương thức present () trong Dòng thời gian và phương thức present () trong Sự tham dự đều khớp.


7

hai tình huống:

1) Đầu tiên, điều đó đã được đề cập, nơi không có giao diện cụ thể nhất

public interface A {
   default void doStuff(){ /* implementation */ }
}

public interface B {
   default void doStuff() { /* implementation */ } 
}

public class C implements A, B {
// option 1: own implementation
// OR
// option 2: use new syntax to call specific interface or face compilation error
  void doStuff(){
      B.super.doStuff();
  }
}

2) Thứ hai, khi CÓ giao diện cụ thể hơn:

   public interface A {
       default void doStuff() { /* implementation */ } 
    }

    public interface B extends A {
       default void doStuff() { /* implementation */ } 
    }

    public class C implements A, B {
    // will use method from B, as it is "closer" to C
    }

4

Câu trả lời của tôi cho câu hỏi của bạn là: Có, đó là một dạng đa thừa kế, vì bạn có thể thừa kế hành vi từ các bậc cha mẹ khác nhau. Điều còn thiếu là kế thừa các trạng thái, tức là các thuộc tính.

Có, nhưng bạn có thể thêm getters và setters vào giao diện của mình mà các lớp triển khai sau đó phải triển khai. Tuy nhiên, các lớp triển khai không kế thừa các thuộc tính. Vì vậy, AFAICS, nó giống như một giải pháp kiểu đặc điểm hơn là một giải pháp kiểu đa kế thừa.


4

Tóm lại: đó là lỗi thời gian biên dịch, phải ghi đè phương thức bằng tay trong quá trình thực hiện.


Mục đích của phương pháp mặc định

Mục đích chính của việc giới thiệu phương thức mặc định trong Java 8 là làm cho giao diện có thể mở rộng mà không phá vỡ các triển khai hiện có (có rất nhiều thư viện Java của bên thứ ba).

multiple inheritancegiống như trong C ++ thực sự là nhằm mục đích tránh, đó chắc chắn không phải là mục đích của phương thức mặc định trong Java.


Cách ghi đè

2 lựa chọn:

  • Ghi đè phương thức, với logic riêng của nó.
  • Ghi đè phương thức, gọi một trong các phương thức của giao diện thông qua super, định dạng:<interface_name>.super.<method_name>();

Lời khuyên:

  • Phương thức từ giao diện được mặc định là công khai, vì vậy đừng quên thêm publictừ khóa khi ghi đè nó.

2

Nếu ai đó vẫn đang tìm kiếm câu trả lời, trong trường hợp một lớp triển khai hai giao diện với cùng một phương thức mặc định thì lớp đó cần phải giải quyết sự phân biệt bằng cách cung cấp một triển khai của riêng nó. Xem hướng dẫn này để biết thêm chi tiết về cách hoạt động của kế thừa trong các phương thức mặc định.


0

"Làm thế nào chúng ta sẽ phân biệt các phương pháp" là một câu hỏi được đặt trên Stackoverflow và đề cập đến câu hỏi này các phương thức cụ thể trong giao diện Java1.8

Sau đây là một ví dụ sẽ trả lời câu hỏi đó:

interface A{
default public void m(){
System.out.println("Interface A: m()");
}
}

interface B{
default public void m(){
System.out.println("Interface B: m()");
}
}

 class C implements A,B { 

 public void m(){
  System.out.println("Concrete C: m()");   
 }

public static void main(String[] args) {
   C aC = new C();
   aC.m();
   new A(){}.m();
   new B(){}.m();
}
}

Lớp C ở trên phải triển khai phương thức cụ thể của riêng nó đối với các giao diện A và B. Cụ thể là:

 public void m(){
  System.out.println("Interface C: m()");   
 }

Để gọi một thực hiện cụ thể của một phương pháp từ một giao diện cụ thể , bạn có thể nhanh chóng các giao diệngọi một cách rõ ràng các phương pháp cụ thể về điều đó giao diện

Ví dụ, đoạn mã sau gọi việc triển khai cụ thể của phương thức m () từ giao diện A :

new A(){}.m();

Kết quả của phần trên sẽ là:

Giao diện A: m ()


-1

Theo như tôi thấy, nó không phải là đa thừa kế vì chúng không có quốc tịch. Vì vậy, các phương thức mở rộng ảo không hỗ trợ đầy đủ chức năng của đối tượng hoặc lớp.

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.