2015-10-14 17 views
5

Câu hỏi từ một cuốn sách:Java 8 - Phương pháp mặc định - mối quan tâm đối với mã di sản

Trong quá khứ (pre-Java 8), bạn được cho biết rằng đó là hình thức xấu để thêm phương pháp để một giao diện vì nó sẽ phá vỡ mã hiện có. Bây giờ bạn được thông báo rằng bạn có thể thêm các phương thức mới, miễn là bạn cũng cung cấp triển khai mặc định.

  1. Làm cách nào an toàn? Mô tả một kịch bản trong đó phương thức stream mới của giao diện Collection làm cho mã kế thừa không biên dịch được.
  2. Còn về tính tương thích nhị phân thì sao? Sẽ mã di sản từ một tập tin JAR vẫn chạy?"

câu trả lời của tôi là như sau nhưng tôi không hoàn toàn chắc chắn về họ.

  1. Đó là an toàn chỉ khi mã di sản không cung cấp một phương pháp với cùng một tên stream và có cùng chữ ký (ví dụ: trong một lớp cũ thực hiện Collection) .Nếu không, mã cũ cũ này sẽ thất bại trong việc biên dịch
  2. Tôi nghĩ khả năng tương thích nhị phân được giữ nguyên, mã kế thừa từ tệp JAR cũ sẽ vẫn chạy Nhưng tôi không có lý lẽ rõ ràng nào về thi S.

Có ai có thể xác nhận hoặc từ chối các câu trả lời này hoặc chỉ thêm một số đối số, tham chiếu hoặc rõ ràng hơn cho các câu trả lời này không?

+0

[Related] (http://stackoverflow.com/a/22618640/335858). – dasblinkenlight

+1

Làm như vậy trong khi vẫn duy trì tính tương thích nhị phân là động lực chính của việc thêm các phương thức mặc định vào ngôn ngữ.Thêm một mặc định cho một phương thức hiện có là nhị phân và nguồn tương thích; thêm một phương thức mới với mặc định là nhị phân và nguồn tương thích (tương tác modulo với các phương thức xung đột trong các lớp con - điều này có các đặc tính tương thích giống nhau để thêm một phương thức mới vào một lớp không phải là cuối cùng.) –

+1

Trong khi khả năng tương thích nhị phân được giữ nguyên, vẫn có thể vấn đề phát sinh, khi nó tương tác với hành vi thư viện JRE, như trong [kịch bản này] (http://stackoverflow.com/q/26816650/2711488). Bạn cũng có thể xem xét rằng một phương thức có thể có chữ ký * tương thích *, do đó, bắt đầu ghi đè lên một phương thức 'default' mới mà không có ý định ... – Holger

Trả lời

8
  1. Phương pháp stream() mặc định mới trong Collection trả về một Stream<E>, cũng là một loại mới trong Java 8. Legacy mã sẽ không biên dịch nếu nó chứa một phương thức stream() với chữ ký giống nhau, nhưng trở về cái gì khác, dẫn đến một xung đột các loại trả về.

  2. Mã cũ sẽ tiếp tục chạy miễn là mã không được biên dịch lại.

Thứ nhất, trong 1,7, thiết lập như sau:

public interface MyCollection { 
    public void foo(); 
} 

public class Legacy implements MyCollection { 
    @Override 
    public void foo() { 
     System.out.println("foo"); 
    } 

    public void stream() { 
     System.out.println("Legacy"); 
    } 
} 

public class Main { 
    public static void main(String args[]) { 
     Legacy l = new Legacy(); 
     l.foo(); 
     l.stream(); 
    } 
} 

Với -source 1.7 -target 1.7, đây biên dịch và chạy:

$ javac -target 1.7 -source 1.7 Legacy.java MyCollection.java Main.java 
$ java Main 
foo 
Legacy 

Bây giờ trong 1,8, chúng ta thêm phương pháp dòng để MyCollection .

public interface MyCollection 
{ 
    public void foo(); 
    public default Stream<String> stream() { 
     return null; 
    } 
} 

Chúng tôi chỉ biên dịch MyCollection trong 1.8.

$ javac MyCollection.java 
$ java Main 
foo 
Legacy 

Tất nhiên chúng tôi không thể biên dịch lại Legacy.java nữa.

$ javac Legacy.java 
Legacy.java:11: error: stream() in Legacy cannot implement stream() in MyCollection 
    public void stream() 
       ^
    return type void is not compatible with Stream<String> 
1 error 
+5

Lưu ý rằng trường hợp góc tương thích này không phải là mới với các phương thức mặc định; cùng một vấn đề đã có mặt với Java 1.0 nếu bạn thêm một phương thức vào một siêu lớp không tương thích với phương thức có cùng tên trong một số lớp con. Việc thêm các phương thức vào các giao diện với các giá trị mặc định có các đặc tính tương thích chính xác giống như việc thêm các phương thức vào các lớp. –

+3

Tôi nghĩ rằng, các phương pháp xung đột là vấn đề nhỏ hơn khi trình biên dịch phát hiện ra chúng. Một vấn đề lớn hơn xảy ra khi chữ ký không xung đột. Với 'stream()', không thể làm kiểu trả về là một lớp mới. Nhưng hãy nghĩ về 'sort (Comparator)'. Bạn có thể có một phương thức như vậy trong thực thi 'List' tùy chỉnh của bạn trước Java 8 và trước Java 8, việc triển khai thực hiện nó bằng cách ủy quyền cho' Collections.sort' sẽ là hợp lý. Bây giờ, 'Collections.sort' đại biểu cho' List.sort' mà phương thức tiền Java 8 ghi đè mà không có ý định. Trình biên dịch sẽ không cho bạn biết về vấn đề này ... – Holger

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