Ada ide mengapa saya perlu memasukkan literal integer ke (int) di sini?

122

Pada contoh berikut

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

Aku tidak bisa melemparkan -128dengan (Integer)tapi saya dapat menyerahkan (int) -128.

Saya selalu berpikir -128adalah inttipe dan casting itu (int)harus berlebihan.

Kesalahan pada baris dengan i3adalah

cannot find symbol variable Integer

Saya mencoba ini dengan Java 6 update 29 dan Java 7 update 1.

EDIT: Anda mendapatkan perilaku yang sama dengan +128bukannya -128. Tampaknya ada kebingungan antara operator unary dan binary.

Peter Lawrey
sumber
5
apa kompiler Anda? Integer i = -128;ini harus dikompilasi.
bestsss
aneh, Integer i3 = (Integer) (-128);meskipun menurut.
Eng. Fouad
2
@ Eng.Fouad, Peter, simbol unary (+ -) memiliki asosiasi kanan ke kiri dan plus, minus untuk kiri ke kanan. Efek dari -128 akan sama dengan +128 dan menempatkan 0 di depan harus diperbaiki, yaitu 0-128 atau 0 + 128. (tidak bisa menguji atm tapi saya yakin itu akan)
bestsss
Pertanyaan bagus! Saya pribadi ingin melihat referensi JLS untuk resolusi operator unary / binary dan saat cast diperlakukan sebagai ekspresi. Jika tidak, mungkin saja kompiler lain tidak menganggapnya sebagai kesalahan!
Bringer128
1
FYI juga kesalahan yang saya dapatkan di IDE saya adalah di Expression expectedmana Integeritu.
Bringer128

Jawaban:

151

Kompilator mencoba mengurangi 128dari (Integer)alih-alih mentransmisikan -128ke Integer. Tambahkan ()untuk memperbaikinya

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

Menurut BoltClock di komentar para pemeran intberfungsi sebagaimana mestinya, karena itu adalah kata yang dicadangkan dan oleh karena itu tidak dapat ditafsirkan sebagai pengenal, yang masuk akal bagi saya.

Dan Bringer128 menemukan Referensi JLS 15.16 .

 CastExpression:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Seperti yang Anda lihat, mentransmisikan ke tipe primitif membutuhkan apa saja UnaryExpression, sedangkan mentransmisikan ke tipe referensi membutuhkan UnaryExpressionNotPlusMinus. Ini didefinisikan sebelum CastExpression di JLS 15.15 .

Jens Schauder
sumber
31
Saya pikir itu karena intadalah kata kunci di Jawa, tetapi Integertidak. Karena intadalah kata kunci, Anda tidak dapat menggunakannya sebagai pengenal untuk variabel atau kelas, menyisakan satu-satunya kemungkinan yang tersisa untuk itu menjadi typecast. Itu akan menjelaskannya.
BoltClock
@BoltClock Memasukkan komentar Anda dalam jawaban.
Jens Schauder
3
Untuk membuat ini menjadi jawaban yang lebih menarik, apakah Anda ingin menambahkan link saya ke JLS?
Bringer128
3
Kerutan (bagi saya) yang menarik tentang masalah ini adalah bagaimana kita menyelesaikan masalah analogi di C #, yang juga memiliki ambiguitas dalam tata bahasa antara "ekspresi dalam tanda kurung sebagai operan untuk operator pengurangan biner" dan "operator cor di mana operan kanan dari cast adalah ekspresi minus unary ". Lihat bagian 7.7.6 dari spesifikasi C # untuk penjelasan rinci tentang heuristik yang kami gunakan untuk mencoba dan cerdas dalam menyelesaikan ketidakjelasan.
Eric Lippert
1
@BillK Mengapa Anda mengatakan itu? Spesifikasi C # tidak mengacu pada kelebihan beban operator di bagian 7.7.6, jadi itu bukan masalah bagi mereka.
Bringer128
48

Saya menemukan referensi JLS. 15.16 .

 CastExpression:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Seperti yang Anda lihat, mentransmisikan ke tipe primitif membutuhkan apa saja UnaryExpression, sedangkan mentransmisikan ke tipe referensi membutuhkan UnaryExpressionNotPlusMinus. Ini didefinisikan sebelum CastExpression di JLS 15.15 .

Anda perlu mengubah cast menjadi tipe primitif:

... (int) -128;

Atau Anda dapat mengubah ekspresi di sebelah kanan cast menjadi ekspresi unary non-plus-minus:

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or
Bringer 128
sumber
12

Kompilator menafsirkan -sebagai operator dua-arg minus, yaitu mencoba mengurangi 128 dari beberapa nomor lain bernama Integer, tetapi tidak ada variabel seperti itu dalam ruang lingkup.

Ini mengkompilasi:

Integer i3 = (Integer) (-128)
Barend
sumber
Anda dapat menambahkan komentar tentang mengapa (int)membuat perbedaan.
Peter Lawrey
1
Itu karena autoboxing, bukan?
Brian Roach
9

Ini mungkin ada hubungannya dengan penguraian sintaks. Perhatikan itu

Integer i4 = (Integer) (-128); 

bekerja dengan baik.

Secara umum, Anda tidak boleh mentransmisikan ke kelas Integer. Ini melibatkan sesuatu yang disebut auto-boxing, dan dapat menyebabkan beberapa kesalahan kecil dalam kode Anda. Metode yang disukai untuk melakukan apa yang Anda inginkan adalah:

Integer i6 = Integer.valueOf(-128)
Krystian Cybulski
sumber
1
cast to Integer persis seperti gula sintetis untuk valueOf.
bestsss
4
ya, tapi terkadang gula sintetis gagal secara halus. Saya mengalami kesulitan untuk melacak pengecualian pointer nol dalam aplikasi besar karena auto-boxing. Kami memperlakukan auto-boxing sebagai kesalahan untuk menghindari sakit kepala di masa depan. Sihir itu bagus, tetapi jika gagal, kepala akan sakit. Saya merasa lebih baik untuk bersikap eksplisit dan menyelamatkan diri Anda dari sakit kepala.
Krystian Cybulski
NPE adalah b1tch w / outboxing, benar. Terutama kasus seperti for (int i in Collection<Integer>)b / c NPE berada di lokasi yang benar-benar tidak terduga. Saya sebenarnya tidak menggunakan Integer w / autoboxing karena kisaran cache kecil (meskipun dapat ditingkatkan dengan opsi XX) tetapi memiliki kelas yang disebut IntegerProvider (sejak 1.1) untuk melakukan hal yang sama. Menggunakan Map (apapun dari java.util) Integer-> Anything biasanya menghasilkan kinerja yang baik kecuali digunakan untuk kasus-kasus sepele dan hampir selalu ada solusi yang lebih baik.
bestsss
Mentransmisikan int ke Integer tidak akan pernah menyebabkan error apa pun, kecuali heap overflow, mungkin. Namun, kebalikannya tidak benar.
Ingo
@MattBall, saya kurang paham, gula sintetis digunakan secara luas: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 dan suara sintetis lebih baik bagi saya.
bestsss
9

Ini menguraikannya sebagai Integer <minus operator> 128dan tidak menemukan variabel Integer. Anda harus membungkus -128dalam tanda kurung:

Integer i3 = (Integer) (-128);  // compiles
Bohemian
sumber
Saya telah memberikan +1 untuk semua jawaban lainnya karena semuanya juga benar :)
Bohemian
7
Integer i3 = (Integer) (-128);

Masalahnya adalah -kompilator melihatnya sebagai operator.

Brian Roach
sumber
6

Baris 3 diinterpretasikan seperti Anda mencoba mengurangi 128 dari ekspresi di dalam kurung dan ekspresi di dalam kurung bukan dan ekspresi tipe int (Ini memperlakukan '-' sebagai operator '-'). Jika Anda mengubah ekspresi menjadi:

Integer i3 = (Integer) (-128);

maka compiler akan mengerti bahwa '-' adalah unary minus yang menunjukkan integer negatif.

Udi Cohen
sumber
3

Kompilator C # memiliki perilaku yang sama. Ini memberikan petunjuk yang lebih baik mengapa gagal untuk dikompilasi:

Untuk memasukkan nilai negatif, Anda harus memasukkan nilai dalam tanda kurung

JefClaes
sumber