2008-08-07 22 views
26

Tôi thấy điều này trong an answer to another question, khi đề cập đến những thiếu sót của spec java:Điều này thực sự mở rộng so với autoboxing?

Hiện có nhiều thiếu sót và điều này là một chủ đề tế nhị. Kiểm tra this ra:

public class methodOverloading{ 
    public static void hello(Integer x){ 
      System.out.println("Integer"); 
    } 

    public static void hello(long x){ 
      System.out.println("long"); 
    } 

    public static void main(String[] args){ 
     int i = 5; 
     hello(i); 
    } 
} 

Here "dài" sẽ được in (chưa kiểm tra nó bản thân mình), bởi vì trình biên dịch choses> mở rộng hơn autoboxing. Hãy cẩn thận khi sử dụng autoboxing hoặc không sử dụng nó!

Chúng tôi có chắc đây thực sự là ví dụ về mở rộng thay vì tự động đóng hộp hay hoàn toàn khác?

Khi quét ban đầu, tôi đồng ý với tuyên bố rằng đầu ra sẽ là "dài" trên cơ sở i được khai báo là nguyên thủy và không phải là đối tượng. Tuy nhiên, nếu bạn đã thay đổi

hello(long x) 

để

hello(Long x) 

đầu ra sẽ in "Integer"

thực sự Có gì xảy ra ở đây? Tôi không biết gì về trình biên dịch/trình biên dịch bytecode cho java ...

+0

Chắc chắn nó đang mở rộng. Int được mở rộng dài. – EJP

Trả lời

12

Trong trường hợp đầu tiên, bạn có một chuyển đổi mở rộng diễn ra. Điều này có thể được nhìn thấy khi runinng các "javap" chương trình tiện ích (bao gồm w/JDK), trên lớp biên soạn:

public static void main(java.lang.String[]); 
    Code: 
    0: iconst_ 5 
    1: istore_ 1 
    2: iload_ 1 
    3: i2l 
    4: invokestatic #6; //Method hello:(J)V 
    7: return 

} 

Rõ ràng, bạn sẽ thấy I2L, đó là ghi nhớ cho mở rộng Integer-To- Hướng dẫn bytecode dài. Xem tài liệu tham khảo here.

Và trong trường hợp khác, thay thế cho "x dài" với đối tượng "Long x" chữ ký, bạn sẽ có mã này trong phương thức main:

public static void main(java.lang.String[]); 
    Code: 
    0: iconst_ 5 
    1: istore_ 1 
    2: iload_ 1 
    3: invokestatic #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 
    6: invokestatic #7; //Method hello:(Ljava/lang/Integer;)V 
    9: return 

} 

Vì vậy, bạn thấy trình biên dịch đã tạo hướng dẫn Integer.valueOf (int), để hộp nguyên thủy bên trong trình bao bọc.

+5

Tôi nghĩ rõ ràng là Java phải mở rộng trước khi auto-boxing vì mã cũ phụ thuộc vào việc mở rộng và sẽ phá vỡ nếu mã đó đột nhiên thay đổi thành auto-boxing. –

3

Có, hãy thử trong thử nghiệm. Bạn sẽ thấy chữ "dài" được in. Nó được mở rộng vì Java sẽ chọn mở rộng int vào một thời gian dài trước khi nó chọn tự động chuyển nó thành một số nguyên, vì vậy phương thức hello (dài) được chọn để được gọi.

Chỉnh sửa: the original post being referenced.

Chỉnh sửa thêm: Lý do tùy chọn thứ hai sẽ in Số nguyên là vì không có "mở rộng" thành nguyên thủy lớn hơn làm tùy chọn, vì vậy nó PHẢI hộp nó lên, do đó Integer là tùy chọn duy nhất. Hơn nữa, java sẽ chỉ autobox để loại ban đầu, do đó, nó sẽ cung cấp cho một lỗi biên dịch nếu bạn để lại hello (Long) và gỡ bỏ hello (Integer).

1

Một điều thú vị khác với ví dụ này là quá tải phương thức. Sự kết hợp của việc mở rộng kiểu và quá tải phương thức chỉ hoạt động vì trình biên dịch phải đưa ra quyết định chọn phương thức nào.Hãy xem xét ví dụ sau:

public static void hello(Collection x){ 
    System.out.println("Collection"); 
} 

public static void hello(List x){ 
    System.out.println("List"); 
} 

public static void main(String[] args){ 
    Collection col = new ArrayList(); 
    hello(col); 
} 

Không sử dụng loại thời gian chạy là Danh sách, sử dụng loại biên dịch là Bộ sưu tập và do đó in "Bộ sưu tập".

Tôi khuyến khích bạn đọc Effective Java, mở mắt cho một số trường hợp góc của JLS.

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