2014-04-11 42 views
22
public class Primitive { 
    void m(Number b, Number ... a) {} // widening, autoboxing->widening->varargs 

    void m(byte b, Number ... a) {} // unboxing, autoboxing->widening->varargs 

    public static void main(String[] args) { 
     Byte b = 12; 
     Primitive obj = new Primitive(); 
     obj.m(b, 23); 
    } 
} 

Tôi đã tìm kiếm và thấy rằng ưu tiên mở rộng cao hơn unboxing, vì vậy trong lời gọi phương thức trên, phương thức đầu tiên phải được gọi vì tham số thứ hai giống nhau cho cả hai. Nhưng điều này không xảy ra. Plz có thể giải thích?Tại sao phương pháp này quá tải không rõ ràng?

+1

Nó biên dịch cho tôi - bạn đang sử dụng trình biên dịch nào? (Và phiên bản nào?) –

+0

Những ưu tiên này xảy ra trong các bước độc lập. Đầu tiên trực tiếp, sau đó với mở rộng, sau đó unboxing. –

+0

Tôi đang sử dụng jdk 1.6 – Aman

Trả lời

7

Không thể biên dịch trong JDK 1.5, 1.6 và 1.7, nhưng hoạt động trong JDK 1.8.

Cập nhật: Nó có vẻ như thực tế là nó làm việc với JDK8 đầu tiên phiên bản thực sự là một lỗi: Nó làm việc trong JDK 1.8.0_05, nhưng theo this question và câu trả lời bằng cách medvedev1088, mã này sẽ không có biên dịch dài hơn trong 1.8.0_25, đó là hành vi phù hợp với JLS

Tôi không nghĩ rằng đây là lỗi đã được sửa. Thay vào đó, nó là một tác động của các thay đổi có liên quan đến các cơ chế gọi phương thức cho các biểu thức lambda trong Java 8.

Hầu hết mọi người có thể đồng ý rằng phần "Biểu thức yêu cầu phương pháp" là phần phức tạp nhất khó hiểu của Đặc tả Ngôn ngữ Java. Và có thể có cả một đội ngũ kỹ sư quan tâm đến việc kiểm tra chéo và xác thực phần này. Vì vậy, bất kỳ tuyên bố hoặc bất kỳ lý luận cố gắng nên được thực hiện với một hạt rất lớn của muối. (Ngay cả khi nó đến từ các kỹ sư nói trên). Nhưng tôi sẽ cung cấp cho nó một thử, để ít nhất thịt ra những phần có liên quan mà những người khác có thể tham khảo cho một phân tích thêm:

Xét phần về

và xem xét rằng cả hai phương pháp là "phương pháp có khả năng áp dụng" (JLS7/JLS8), sau đó các tiểu mục có liên quan là một trong những khoảng

Đối với JLS 7, nó khẳng định

Phương pháp m là một phương pháp áp dụng biến-arity khi và chỉ khi tất cả các các điều kiện sau đây giữ:

  • Đối với 1 = i < n, loại ei, Ai, có thể được chuyển đổi bằng cách chuyển đổi lời gọi phương thức thành Si.
  • ...

(Các điều kiện khác được đề cập đến hình thức gọi mà không liên quan ở đây, ví dụlời gọi đó thực sự sử dụng các varargs, hoặc lời gọi có liên quan đến generics)

Đề cập đến ví dụ: Một phương pháp được áp dụng cho các biểu tranh luận thực tế b loại Byte khi b có thể được chuyển đổi sang các tham số phương pháp chính thức tương ứng thông qua phương pháp chuyển đổi lời gọi. Theo phần tương ứng về Method Invocation Conversion trong JLS7, các chuyển đổi sau đây được phép:

  • một chuyển đổi danh tính (§5.1.1)
  • chuyển đổi nguyên thủy mở rộng (§5.1.2)
  • một tài liệu tham khảo mở rộng chuyển đổi (§5.1.5)
  • chuyển đổi quyền anh (§5.1.7) theo sau tùy chọn bằng cách mở rộng chuyển đổi tham chiếu
  • chuyển đổi unboxing (§5.1.8) theo sau tùy chọn mở rộng chuyển đổi nguyên thủy.

Rõ ràng, có hai phương pháp được áp dụng theo đặc điểm kỹ thuật này:

  • m(Number b, Number ... a) được áp dụng thông qua mở rộng tham khảo chuyển đổi
  • m(byte b, Number ... a) được áp dụng thông qua chuyển đổi unboxing

Bạn đã đề cập rằng bạn "... nhận thấy rằng ưu tiên mở rộng cao hơn một unboxing ", nhưng điều này không áp dụng ở đây: Các điều kiện được liệt kê ở trên không liên quan đến bất kỳ" ưu tiên "nào. Chúng được liệt kê dưới dạng các tùy chọn khác nhau. Ngay cả khi phương pháp đầu tiên là void m(Byte b, Number ... a), "chuyển đổi danh tính" sẽ được áp dụng, nhưng nó vẫn chỉ được tính là một chuyển đổi có thể là và gây ra lỗi do sự mơ hồ.


Vì vậy, theo như tôi hiểu, điều này giải thích lý do tại sao nó đã làm không làm việc với JDK7. Tôi đã không tìm hiểu chi tiết tại sao nó đã làm làm việc với JDK8. Nhưng định nghĩa về khả năng áp dụng các phương pháp arity biến đổi slighly trong Identify Methods Applicable by Variable Arity Invocation in JLS 8:

Nếu m không phải là một phương pháp chung chung, sau đó m được áp dụng bằng cách gọi arity biến nếu, 1 ≤ i ≤ k, hoặc ei là tương thích trong một bối cảnh yêu cầu lỏng lẻo với Ti hoặc ei không phù hợp với khả năng ứng dụng (§15.12.2.2).

(tôi đã làm chưa lặn sâu hơn vào các định nghĩa của "bối cảnh gọi lỏng lẻo" và phần §15.12.2.2, nhưng điều này có vẻ là sự khác biệt quan trọng ở đây)


Một sang một bên, một lần nữa đề cập đến tuyên bố của bạn rằng bạn "... nhận thấy rằng mức độ ưu tiên mở rộng cao hơn unboxing": Điều này đúng cho các phương pháp làm không liên quan đến varargs (và không yêu cầu chuyển đổi gọi phương thức). Nếu bạn bỏ qua các biến thể trong ví dụ của bạn, thì quá trình tìm kiếm phương thức khớp sẽ bắt đầu trong Phase 1: Identify Matching Arity Methods Applicable by Subtyping.Phương pháp m(Number b) sau đó sẽ được áp dụng cho tham số Byte b do Byte là loại phụ của Number. Sẽ không có lý do gì để đi vào Phase 2: Identify Matching Arity Methods Applicable by Method Invocation Conversion. Trong giai đoạn này, chuyển đổi gọi phương thức thông qua unboxing từ Byte đến byte sẽ được áp dụng, nhưng giai đoạn này không bao giờ đạt được.

+2

Đây là câu hỏi tương tự http://stackoverflow.com/questions/30130720/method-overload-ambiguity-with-java-8-ternary-conditional-and-unboxed-primitives/30137369#30137369 – medvedev1088

+1

@ medvedev1088 Tôi vẫn chưa học chi tiết về các cập nhật liên quan đến "ngữ cảnh yêu cầu" vv Nhưng bây giờ, theo câu hỏi (và câu trả lời của bạn) mà bạn đã liên kết, nó ** có vẻ như ** thực tế là đoạn mã từ đây ** đã làm ** với JDK8 là một lỗi trong các phiên bản JDK8 trước đó, và lỗi này đã được sửa trong phiên bản 8-25 - bạn có đồng ý không? – Marco13

+1

Vâng, tôi đồng ý. Chỉ cần thử nghiệm trên JDK 1.8.0_25 và nó không biên dịch. Và nó không nên theo JLS vì không có cách nào cho trình biên dịch để xác định phương pháp nào cụ thể hơn. Ngoài ra nó đặt ra một câu hỏi quan trọng: liệu JLS có nên được cải thiện hay không và nó có thể được cải thiện như thế nào. Một số lỗi trình biên dịch phản trực giác như một lỗi từ câu hỏi tôi đã liên kết. Bạn nghĩ sao? – medvedev1088

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