2017-02-11 23 views
7

Tôi đã lớp sau:Có phải làm cho kiểu trả về chung với cùng một nhị phân xóa tương thích không?

public abstract Foo { 
    Foo() {} 

    public abstract Foo doSomething(); 

    public static Foo create() { 
    return new SomePrivateSubclassOfFoo(); 
    } 
} 

Tôi muốn thay đổi nó để định nghĩa sau đây:

public abstract Foo<T extends Foo<T>> { 
    Foo() {} 

    public abstract T doSomething(); 

    public static Foo<?> create() { 
    return new SomePrivateSubclassOfFoo(); 
    } 
} 

là sự thay đổi này nhị phân tương thích? I.e., mã sẽ được biên dịch dựa vào phiên bản cũ của lớp học có hoạt động với phiên bản mới mà không cần biên dịch lại không?

Tôi biết rằng tôi cần thay đổi SomePrivateSubclassOfFoo, điều này là ok. Tôi cũng biết rằng thay đổi này sẽ kích hoạt cảnh báo về các loại thô khi mã máy khách cũ được biên dịch, điều này cũng tốt cho tôi. Tôi chỉ muốn đảm bảo rằng mã khách hàng cũ không cần phải được biên dịch lại.

Từ sự hiểu biết của tôi, điều này sẽ là ok vì việc xóa của TFoo và do đó chữ ký của doSomething trong mã byte giống như trước đây. Nếu tôi nhìn vào các chữ ký kiểu nội bộ được in bởi javap -s, tôi thực sự thấy điều này được xác nhận (mặc dù chữ ký loại "không phải nội bộ" được in mà không cần -s khác nhau). Tôi cũng đã thử nghiệm điều này, và nó đã làm việc cho tôi.

Tuy nhiên, Java API Compliance Checker cho tôi biết rằng hai phiên bản không tương thích nhị phân.

Vậy điều gì là chính xác? Liệu JLS có đảm bảo tính tương thích nhị phân ở đây hay chỉ là may mắn trong các thử nghiệm của tôi? (Tại sao điều này có thể xảy ra?)

Trả lời

4

Vâng có mã của bạn dường như không làm hỏng khả năng tương thích nhị phân.
tôi thấy những sau khi một số bò/đọc
http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.4.5 mà nói: -

Thêm hoặc loại bỏ một số loại của một lớp không, trong chính nó, có bất kỳ ý nghĩa đối với khả năng tương thích nhị phân.
...
Thay đổi giới hạn đầu tiên của tham số kiểu của lớp có thể thay đổi xóa (§4.6) của bất kỳ thành viên nào sử dụng thông số loại đó và điều này có thể ảnh hưởng đến khả năng tương thích nhị phân. Sự thay đổi của một ràng buộc như vậy là tương tự với sự thay đổi của ràng buộc đầu tiên của một tham số kiểu của một phương thức hoặc hàm tạo (§13.4.13).

Và đây http://wiki.eclipse.org/Evolving_Java-based_APIs_2#Turning_non-generic_types_and_methods_into_generic_ones làm rõ thêm: -

Theo những câu chuyện tương thích đặc biệt, trình biên dịch Java đối xử với một kiểu thô như một tài liệu tham khảo để tẩy xoá của loại. Một kiểu hiện có có thể được phát triển thành một kiểu generic bằng cách thêm các tham số kiểu vào khai báo kiểu và sử dụng một cách khôn ngoan các biến kiểu vào các chữ ký của các phương thức và các trường hiện có của nó. Miễn là tẩy xoá giống như khai báo tương ứng trước khi generification, sự thay đổi là nhị phân tương thích với mã hiện có.

Vì vậy, bạn không có vấn đề gì kể từ bây giờ vì đây là lần đầu tiên bạn mở rộng lớp học đó.

Nhưng hãy nhớ như doc trên cũng nói: -

Nhưng, cũng ghi nhớ rằng có những trở ngại nghiêm trọng về cách một loại hoặc phương pháp mà đã là chung chung có thể được phát triển compatibly đối với các tham số kiểu của nó (xem các bảng ở trên). Vì vậy, nếu bạn có kế hoạch để mở rộng một API, hãy nhớ rằng bạn chỉ nhận được một cơ hội (phát hành), để làm cho nó đúng. Đặc biệt, nếu bạn thay đổi loại trong chữ ký API từ "Danh sách" thô thành "Danh sách <? >" hoặc "Danh sách < Đối tượng >", bạn sẽ bị khóa vào quyết định đó. Đạo đức là việc mở rộng một API hiện tại là một cái gì đó cần được xem xét từ góc độ của API như một tổng thể chứ không phải từng phần trên cơ sở từng phương thức hoặc từng lớp.

Vì vậy, tôi nghĩ, không sao để thực hiện thay đổi này lần đầu tiên nhưng bạn chỉ có một cơ hội để tận dụng nó!

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