Sự khác biệt về tính năng tự động mở hộp giữa Java 6 và Java 7


107

Tôi đã nhận thấy sự khác biệt về hành vi tự động mở hộp giữa Java SE 6 và Java SE 7. Tôi tự hỏi tại sao lại như vậy, vì tôi không thể tìm thấy bất kỳ tài liệu nào về những thay đổi trong hành vi này giữa hai phiên bản này.

Đây là một ví dụ đơn giản:

Object[] objs = new Object[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

Điều này biên dịch tốt với javac từ Java SE 7. Tuy nhiên, nếu tôi cung cấp cho trình biên dịch đối số "-source 1.6", tôi sẽ gặp lỗi ở dòng cuối cùng:

inconvertible types
found   : java.lang.Object
required: int

Tôi đã thử tải xuống Java SE 6 để biên dịch với trình biên dịch phiên bản gốc 6 (không có bất kỳ tùy chọn -source nào). Nó đồng ý và đưa ra lỗi tương tự như trên.

Vì vậy, những gì cho? Từ một số thử nghiệm khác, có vẻ như việc mở hộp trong Java 6 chỉ có thể mở hộp các giá trị rõ ràng (tại thời điểm biên dịch) thuộc loại được đóng hộp. Ví dụ: điều này hoạt động trong cả hai phiên bản:

Integer[] objs = new Integer[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

Vì vậy, có vẻ như giữa Java 6 và 7, tính năng mở hộp đã được cải tiến để nó có thể ép và mở hộp các loại đối tượng trong một lần chuyển mà không cần biết (tại thời điểm biên dịch) rằng giá trị có thuộc loại được đóng hộp thích hợp hay không. Tuy nhiên, đọc qua Đặc tả ngôn ngữ Java hoặc các bài đăng trên blog được viết vào thời điểm Java 7 ra mắt, tôi không thể thấy bất kỳ thay đổi nào của điều này, vì vậy tôi tự hỏi thay đổi là gì và "tính năng" này được gọi là gì ?

Chỉ là sự tò mò: Do sự thay đổi, có thể kích hoạt các hộp mở "sai":

Object[] objs = new Float[2];
objs[0] = new Float(5);
int myInt = (int)objs[0];

Điều này biên dịch tốt nhưng cung cấp một ClassCastException trong thời gian chạy.

Bất kỳ tài liệu tham khảo về điều này?


17
Hấp dẫn. Một thành phần mới cho mớ hỗn độn hộp tự động. Tôi nghĩ ví dụ của bạn có thể đơn giản và rõ ràng hơn với một đối tượng duy nhất thay vì một mảng. Integer obj = new Integer(2); int x = (int)obj;: Công trình trên Java 7, mang đến cho lỗi trên Java 6.
leonbloy

1
Bạn đang sử dụng JDK nào? Nó cũng có thể có để làm với các nhà cung cấp khác nhau ...
barfuin

1
@leonbloy: Điểm tốt về sự đơn giản hóa, tôi đã đơn giản hóa nó phần nào (từ mã gốc của tôi) nhưng bằng cách nào đó đã dừng lại quá sớm!
Morty

@Thomas: Đó là JDK mới nhất (cho từng phiên bản) từ Oracle mà tôi đã sử dụng.
Morty

2
Một lý do khác để không bao giờ sử dụng autoboxing.
gyorgyabraham

Câu trả lời:


92

Có vẻ như ngôn ngữ trong phần 5.5 Truyền chuyển đổi JLS Java 7 đã được cập nhật so với cùng một phần trong JLS Java 5/6 , có thể là để làm rõ các chuyển đổi được phép.

Java 7 JLS nói

Một biểu thức của kiểu tham chiếu có thể trải qua quá trình truyền chuyển đổi sang kiểu nguyên thủy mà không có lỗi, bằng cách chuyển đổi mở hộp.

Java 5/6:

Giá trị của một kiểu tham chiếu có thể được chuyển sang kiểu nguyên thủy bằng cách chuyển đổi mở hộp (§5.1.8).

Java 7 JLS cũng chứa một bảng (bảng 5.1) các chuyển đổi được phép (bảng này không có trong Java 5/6 JLS) từ các kiểu tham chiếu đến các kiểu nguyên thủy. Điều này liệt kê rõ ràng các lần truyền từ Đối tượng đến nguyên thủy dưới dạng chuyển đổi tham chiếu thu hẹp với tính năng mở hộp.

Lý do được giải thích trong email này :

Điểm mấu chốt: Nếu thông số kỹ thuật. cho phép (Đối tượng) (int) nó cũng phải cho phép (int) (Đối tượng).


35

Bạn đúng rồi; nói một cách đơn giản hơn:

Object o = new Integer(1234);
int x = (int) o;

Điều này hoạt động trong Java 7, nhưng gây ra lỗi biên dịch trong Java 6 trở xuống. Thật kỳ lạ, tính năng này không được ghi nhận một cách nổi bật; ví dụ, nó không được đề cập ở đây . Sẽ gây tranh cãi nếu đó là một tính năng mới hay một bản sửa lỗi (hoặc một lỗi mới?), Hãy xem một số thông tin liên quan và thảo luận . Sự đồng thuận dường như chỉ ra sự không rõ ràng trong thông số ban đầu, dẫn đến việc triển khai hơi không chính xác / không nhất quán trên Java 5/6, đã được sửa trong 7, vì nó rất quan trọng đối với việc triển khai JSR 292 (Các ngôn ngữ được đánh máy động).

Tính năng autoboxing trong Java hiện có thêm một số bẫy và điều bất ngờ. Ví dụ

Object obj = new Integer(1234);
long x = (long)obj;

sẽ biên dịch, nhưng không thành công (với ClassCastException) trong thời gian chạy. Thay vào đó, điều này sẽ hoạt động:

long x = (long)(int)obj;


2
Cảm ơn vì câu trả lời. Tuy nhiên, có một điều tôi không hiểu. Đây là phần làm rõ về JLS và các triển khai kèm theo (xem phần thảo luận qua thư), nhưng tại sao điều đó lại được thực hiện để chứa các ngôn ngữ được đánh máy khác trên JVM? Rốt cuộc, đó là một sự thay đổi đối với ngôn ngữ, không phải VM: hành vi ép kiểu của VM hoạt động như mọi khi, trình biên dịch thực hiện tính năng này bằng cách sử dụng cơ chế hiện có để truyền sang Integer và gọi .intValue (). Vì vậy, làm thế nào điều này có thể thay đổi trong ngôn ngữ Java thích hợp, giúp chạy các ngôn ngữ khác trên máy ảo? Tôi đồng ý liên kết của bạn gợi ý điều này, chỉ là tự hỏi.
Morty
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.