Bất kỳ ý tưởng tại sao tôi cần truyền một số nguyên theo nghĩa đen thành (int) ở đây?


122

Trong ví dụ sau

int i = -128;
Integer i2 = (Integer) i; // compiles

Integer i3 = (Integer) -128; /*** Doesn't compile ***/

Integer i4 = (Integer) (int) -128; // compiles
Integer i4 = -128; // compiles
Integer i5 = (int) -128; // compiles
Integer i6 = (Integer) (-128); // compiles
Integer i7 = (Integer) 0-128; // compiles

Tôi không thể cast -128với (Integer)nhưng tôi có thể cast (int) -128.

Tôi luôn nghĩ rằng đó -128là một intloại và đúc nó với (int)nên là thừa.

Lỗi trên dòng với i3

cannot find symbol variable Integer

Tôi đã thử điều này với Java 6 bản cập nhật 29 và Java 7 bản cập nhật 1.

CHỈNH SỬA: Bạn nhận được cùng một hành vi với +128thay vì -128. Dường như có sự nhầm lẫn giữa toán tử đơn phân và nhị phân.


5
trình biên dịch của bạn là gì? Integer i = -128;điều này nên biên dịch, mặc dù.
bestsss

wierd, Integer i3 = (Integer) (-128);tuân thủ mặc dù.
Eng.Fouad

2
@ Eng.Fouad, Peter, các ký hiệu một ngôi (+ -) có tính liên kết từ phải sang trái và cộng, trừ là từ trái sang phải. Hiệu ứng của -128 sẽ giống như +128 và đặt số 0 ở phía trước sẽ sửa, tức là 0-128 hoặc 0 + 128. (không thể kiểm tra atm nhưng tôi cá là nó sẽ làm được)
bestsss

Câu hỏi hay! Cá nhân tôi muốn xem một tham chiếu JLS để phân giải các toán tử đơn phân / nhị phân và khi một phép ép kiểu được coi như một biểu thức. Nếu không, có thể các trình biên dịch khác không coi đó là lỗi!
Bringer128

1
Ngoài ra, lỗi mà tôi gặp phải trong IDE của mình là Expression expectedở đâu Integer.
Bringer128

Câu trả lời:


151

Trình biên dịch cố gắng trừ 128từ (Integer)thay vì truyền -128sang Integer. Thêm ()để sửa nó

Integer i3 = (Integer) -128; // doesn't compile
Integer i3 = (Integer) (-128); // compiles

Theo BoltClock trong các nhận xét, dàn diễn viên sẽ inthoạt động như dự định, bởi vì nó là một từ dành riêng và do đó không thể được hiểu như một định danh, điều này có ý nghĩa với tôi.

Và Bringer128 đã tìm thấy Tham chiếu JLS 15.16 .

 CastExpression:
    (Tùy chọn PrimitiveType Dims ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Như bạn có thể thấy, truyền tới một kiểu nguyên thủy yêu cầu bất kỳ UnaryExpression, trong khi truyền tới một kiểu tham chiếu yêu cầu a UnaryExpressionNotPlusMinus. Chúng được xác định ngay trước CastExpression tại JLS 15.15 .


31
Tôi nghĩ đó là vì intlà một từ khóa trong Java, nhưng Integerkhông phải. Vì intlà một từ khóa, bạn không thể sử dụng nó như một định danh cho một biến hoặc một lớp, để lại khả năng duy nhất cho nó là một typecast. Điều đó sẽ giải thích nó.
BoltClock

@BoltClock Kết hợp nhận xét của bạn trong câu trả lời.
Jens Schauder

3
Để làm cho câu trả lời này thậm chí còn xuất sắc hơn, bạn có muốn thêm liên kết của tôi vào JLS không?
Bringer128

3
Một điểm thú vị (đối với tôi) về vấn đề này là cách chúng ta giải quyết vấn đề tương tự trong C #, vấn đề này cũng có sự không rõ ràng trong ngữ pháp giữa "biểu thức được đặt trong ngoặc đơn như một toán hạng đối với toán tử trừ nhị phân" và "toán tử ép kiểu trong đó toán hạng bên phải của ép kiểu là một biểu thức trừ một bậc ". Xem phần 7.7.6 của đặc điểm kỹ thuật C # để biết mô tả chi tiết về phương pháp phỏng đoán mà chúng tôi sử dụng để thử và thông minh trong việc giải quyết sự mơ hồ.
Eric Lippert

1
@BillK Tại sao bạn lại nói như vậy? Thông số C # không đề cập đến việc nạp chồng toán tử trong phần 7.7.6, vì vậy nó không phải là vấn đề đối với chúng.
Bringer128,

48

Tôi đã tìm thấy tài liệu tham khảo JLS. 15,16 .

 CastExpression:
    (Tùy chọn PrimitiveType Dims ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Như bạn có thể thấy, truyền tới một kiểu nguyên thủy yêu cầu bất kỳ UnaryExpression, trong khi truyền tới một kiểu tham chiếu yêu cầu a UnaryExpressionNotPlusMinus. Chúng được xác định ngay trước CastExpression tại JLS 15.15 .

Bạn cần thay đổi kiểu truyền thành kiểu nguyên thủy:

... (int) -128;

Hoặc bạn có thể thay đổi biểu thức ở bên phải của phép ép kiểu thành biểu thức một bậc không cộng trừ:

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or

12

Trình biên dịch hiểu -là toán tử trừ hai đối số, tức là nó đang cố gắng trừ 128 từ một số khác được đặt tên Integer, nhưng không có biến nào như vậy trong phạm vi.

Điều này biên dịch:

Integer i3 = (Integer) (-128)

Bạn có thể thêm nhận xét về lý do tại sao (int)tạo ra sự khác biệt.
Peter Lawrey

1
Đó là do hộp tự động, không?
Brian Roach,

9

Điều này có thể liên quan đến phân tích cú pháp. Thông báo rằng

Integer i4 = (Integer) (-128); 

hoạt động tốt.

Nói chung, bạn không nên ép kiểu sang lớp Integer. Điều này liên quan đến một thứ được gọi là tự động đấm bốc và có thể gây ra một số lỗi nhỏ trong mã của bạn. Phương pháp ưa thích để làm những gì bạn muốn là:

Integer i6 = Integer.valueOf(-128)

1
cast to Integer chính xác là đường tổng hợp cho valueOf.
bestsss

4
có, nhưng đôi khi đường tổng hợp không thành công theo những cách tinh vi. Tôi đã gặp một số khó khăn để theo dõi các ngoại lệ con trỏ null trong các ứng dụng lớn do tính năng tự động đóng gói. Chúng tôi đã tiến xa hơn đến việc coi quyền tự động là lỗi để đỡ đau đầu trong tương lai. Phép thuật là tốt đẹp, nhưng khi nó thất bại, đầu rất đau. Tôi thấy tốt hơn là nên nói rõ ràng và đỡ đau đầu cho chính mình.
Krystian Cybulski

NPE là b1tch w / outboxing, đúng. Những trường hợp đặc biệt như for (int i in Collection<Integer>)b / c NPE đang ở một vị trí hoàn toàn bất ngờ. Tôi thực sự không sử dụng Integer w / autoboxing vì phạm vi bộ nhớ cache nhỏ (mặc dù nó có thể được tăng tùy chọn w / XX) nhưng có một lớp được gọi là IntegerProvider (kể từ 1.1) để thực hiện những công việc tương tự. Sử dụng Bản đồ (bất kỳ từ java.util) Integer-> Mọi thứ thường là một cú đánh hiệu suất trừ khi nó được sử dụng cho các trường hợp nhỏ và hầu như luôn có giải pháp tốt hơn.
bestsss

Truyền int sang Integer không bao giờ có thể gây ra bất kỳ lỗi nào, có lẽ ngoại trừ lỗi tràn heap. Tuy nhiên, điều ngược lại không đúng.
Ingo

@MattBall, tôi không hiểu lắm, đường tổng hợp được sử dụng rộng rãi: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 và đường tổng hợp nghe tốt hơn đối với tôi.
bestsss

9

Nó phân tích cú pháp nó Integer <minus operator> 128và không tìm thấy biến Integer. Bạn sẽ cần đặt -128trong dấu ngoặc vuông:

Integer i3 = (Integer) (-128);  // compiles

Tôi đã tặng +1 cho tất cả các câu trả lời khác vì chúng cũng đúng :)
Bohemian

7
Integer i3 = (Integer) (-128);

Vấn đề là -trình biên dịch coi nó như một toán tử.


6

Dòng 3 được hiểu giống như bạn đang cố gắng trừ 128 khỏi biểu thức trong ngoặc và biểu thức trong ngoặc không phải và biểu thức kiểu int (Nó xử lý '-' như một toán tử '-'). Nếu bạn thay đổi biểu thức thành:

Integer i3 = (Integer) (-128);

thì trình biên dịch sẽ hiểu '-' là số trừ một bậc cho biết một số nguyên âm.


3

Trình biên dịch C # có hành vi tương tự. Nó cung cấp một gợi ý tốt hơn tại sao nó không biên dịch được:

Để truyền giá trị âm, bạn phải đặt giá trị trong dấu ngoặc đơn

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.