Batasnya int
adalah dari -2147483648 hingga 2147483647.
Jika saya masukan
int i = 2147483648;
maka Eclipse akan meminta garis bawah merah di bawah "2147483648".
Tetapi jika saya melakukan ini:
int i = 1024 * 1024 * 1024 * 1024;
itu akan dikompilasi dengan baik.
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
Mungkin itu pertanyaan mendasar di Jawa, tapi saya tidak tahu mengapa varian kedua tidak menghasilkan kesalahan.
2147483648
: literal ini tidak masuk akal.Jawaban:
Tidak ada yang salah dengan pernyataan itu; Anda hanya mengalikan 4 angka dan menugaskannya ke int, kebetulan ada overflow. Ini berbeda dari menetapkan satu literal , yang akan diperiksa batasnya pada waktu kompilasi.
Ini adalah literal di luar batas yang menyebabkan kesalahan, bukan tugas :
Sebaliknya
long
literal dapat dikompilasi dengan baik:Perhatikan bahwa, pada kenyataannya, hasilnya adalah masih dihitung pada saat kompilasi karena
1024 * 1024 * 1024 * 1024
merupakan ekspresi konstan :menjadi:
Perhatikan bahwa hasilnya (
0
) hanya dimuat dan disimpan, dan tidak ada multiplikasi yang terjadi.Dari JLS §3.10.1 (terima kasih kepada @ChrisK karena telah menyampaikannya di komentar):
sumber
-1 + 1
, itu tidak berbahaya; tetapi untuk1024^4
itu dapat membutakan orang-orang dengan hasil yang sama sekali tidak terduga, jauh dari apa yang mereka harapkan untuk dilihat. Saya pikir setidaknya harus ada peringatan atau catatan untuk pengguna, dan jangan diam-diam mengabaikannya.1024 * 1024 * 1024 * 1024
dan2147483648
tidak memiliki nilai yang sama di Jawa.Sebenarnya,
2147483648
BUKAN BAHKAN NILAI (walaupun2147483648L
) di Jawa. Kompiler benar-benar tidak tahu apa itu, atau bagaimana menggunakannya. Jadi itu merengek.1024
adalah int yang valid di Java, dan validint
dikalikan dengan valid lainint
, selalu validint
. Bahkan jika itu bukan nilai yang sama yang Anda harapkan secara intuitif karena perhitungannya akan meluap.Contoh
Pertimbangkan contoh kode berikut:
Apakah Anda berharap ini menghasilkan kesalahan kompilasi? Itu menjadi sedikit lebih licin sekarang.
Bagaimana jika kita meletakkan satu loop dengan 3 iterasi dan dikalikan dalam loop?
Kompiler diizinkan untuk mengoptimalkan, tetapi tidak dapat mengubah perilaku program saat melakukannya.
Beberapa info tentang bagaimana kasus ini ditangani:
Di Jawa dan banyak bahasa lainnya, integer akan terdiri dari jumlah bit yang tetap. Perhitungan yang tidak sesuai dengan jumlah bit yang diberikan akan melimpah ; perhitungan pada dasarnya dilakukan modulus 2 ^ 32 di Jawa, setelah itu nilai diubah kembali menjadi bilangan bulat yang ditandatangani .
Bahasa atau API lain menggunakan jumlah bit dinamis (
BigInteger
di Jawa), naikkan pengecualian atau setel nilai ke nilai ajaib seperti bukan-angka-.sumber
2147483648
BUKAN BAHKAN NILAI (walaupun2147483648L
begitu)," benar-benar menguatkan poin yang coba dibuat oleh @arshajii.1024 * 1024 * 1024 * 1024
penanganannya, saya benar-benar ingin menekankan bahwa itu tidak sama dengan menulis2147473648
. Ada banyak cara (dan Anda telah mendaftarkan beberapa) yang dapat ditangani oleh suatu bahasa. Ini cukup terpisah, dan bermanfaat. Jadi saya akan meninggalkannya. Banyak informasi menjadi semakin diperlukan ketika Anda memiliki jawaban berperingkat tinggi pada pertanyaan populer.Perilaku yang Anda sarankan - yaitu, produksi pesan diagnostik ketika perhitungan menghasilkan nilai yang lebih besar dari nilai terbesar yang dapat disimpan dalam bilangan bulat - adalah fitur . Agar Anda dapat menggunakan fitur apa pun, fitur tersebut harus dipikirkan, dianggap sebagai ide yang baik, dirancang, ditentukan, diterapkan, diuji, didokumentasikan, dan dikirimkan kepada pengguna.
Untuk Java, satu atau lebih hal dalam daftar itu tidak terjadi, dan karena itu Anda tidak memiliki fitur. Saya tidak tahu yang mana; Anda harus bertanya kepada desainer Java.
Untuk C #, semua hal itu memang terjadi - sekitar empat belas tahun yang lalu sekarang - dan program yang sesuai dalam C # telah menghasilkan kesalahan sejak C # 1.0.
sumber
Selain jawaban arshaji, saya ingin menunjukkan satu hal lagi:
Bukan penugasan yang menyebabkan kesalahan tetapi hanya penggunaan literal . Ketika Anda mencoba
Anda akan melihatnya juga menyebabkan kesalahan kompilasi karena sisi kanan masih
int
-literal dan di luar jangkauan.Jadi operasi dengan
int
-nilai (dan itu termasuk tugas) dapat meluap tanpa kesalahan kompilasi (dan tanpa kesalahan runtime juga), tetapi kompilator tidak bisa menangani literal yang terlalu besar.sumber
A: Karena itu bukan kesalahan.
Latar Belakang: Perkalian
1024 * 1024 * 1024 * 1024
akan menyebabkan melimpah. Overflow seringkali merupakan bug. Bahasa pemrograman yang berbeda menghasilkan perilaku yang berbeda ketika terjadi luapan. Misalnya, C dan C ++ menyebutnya "perilaku tidak terdefinisi" untuk bilangan bulat yang ditandatangani, dan perilaku tersebut didefinisikan sebagai bilangan bulat tak bertanda (ambil hasil matematika, tambahkanUINT_MAX + 1
asalkan hasilnya negatif, kurangiUINT_MAX + 1
asalkan hasilnya lebih besar dariUINT_MAX
).Dalam kasus Java, jika hasil operasi dengan
int
nilai - nilai tidak dalam rentang yang diizinkan, Java secara konseptual menambah atau mengurangi 2 ^ 32 sampai hasilnya dalam kisaran yang diizinkan. Jadi pernyataan itu sepenuhnya sah dan tidak salah. Itu tidak menghasilkan hasil yang Anda harapkan.Anda pasti dapat berdebat apakah perilaku ini bermanfaat, dan apakah kompiler harus memberi Anda peringatan. Saya akan mengatakan secara pribadi bahwa peringatan akan sangat berguna, tetapi kesalahan akan salah karena itu adalah hukum Jawa.
sumber