Apa arti dari double tilde (~~) di Jawa?

192

Saat menelusuri kode sumber Guava, saya menemukan potongan kode berikut (bagian dari implementasi hashCodeuntuk kelas batin CartesianSet):

int adjust = size() - 1;
for (int i = 0; i < axes.size(); i++) {
    adjust *= 31;
    adjust = ~~adjust;
    // in GWT, we have to deal with integer overflow carefully
}
int hash = 1;
for (Set<E> axis : axes) {
    hash = 31 * hash + (size() / axis.size() * axis.hashCode());

    hash = ~~hash;
}
hash += adjust;
return ~~hash;

Kedua adjustdan hashyang ints. Dari apa yang saya ketahui tentang Java, ~berarti negasi bitwise, jadi adjust = ~~adjustdan hash = ~~hashharus membiarkan variabel tidak berubah. Menjalankan tes kecil (dengan pernyataan diaktifkan, tentu saja),

for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
    assert i == ~~i;
}

mengkonfirmasi ini. Dengan asumsi bahwa para pria jambu biji tahu apa yang mereka lakukan, pasti ada alasan bagi mereka untuk melakukan ini. Pertanyaannya adalah apa?

EDIT Seperti yang ditunjukkan dalam komentar, tes di atas tidak termasuk kasus di mana isama dengan Integer.MAX_VALUE. Karena i <= Integer.MAX_VALUEselalu benar, kita perlu memeriksa kasing di luar loop untuk mencegahnya berulang selamanya. Namun, garisnya

assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;

menghasilkan peringatan kompiler "Membandingkan ekspresi identik", yang cukup banyak berhasil.

Halle Knast
sumber
42
@dr_andonuts Guava adalah perpustakaan yang cukup standar untuk disertakan dalam proyek akhir-akhir ini - saya pikir saran untuk lari jauh salah tempat.
yshavit
4
Penegasan tidak memeriksa kasing tepi Integer.MAX_VALUE. Berbeda dengan -(-Integer.MIN_VALUE) != Integer.MIN_VALUE.
Franky
3
@Franky Apa kata maaartinus. -Integer.MIN_VALUEmembungkus Integer.MIN_VALUE, jadi meniadakan itu lagi hanya menghasilkan Integer.MIN_VALUElagi.
2
@maaartinus, @hvd, terima kasih sudah menunjukkannya. Sekarang saya ingat itu -x = (~x) + 1.
Franky
7
@dr_andonuts Trolling? Mengapa melarikan diri dari hal-hal yang tidak Anda mengerti. Inilah tujuan dari StackOverflow di sini: untuk membantu Anda belajar.
Jared Burrows

Jawaban:

245

Di Jawa, tidak ada artinya.

Tetapi komentar itu mengatakan bahwa baris ini khusus untuk GWT, yang merupakan cara untuk mengkompilasi Java ke JavaScript.

Dalam JavaScript, bilangan bulat adalah jenis seperti bilangan ganda yang bertindak sebagai bilangan bulat. Mereka memiliki nilai maksimal 2 ^ 53, misalnya. Tetapi operator bitwise memperlakukan angka seolah-olah mereka 32-bit, yang persis seperti yang Anda inginkan dalam kode ini. Dengan kata lain, ~~hashkatakan "perlakukan hashsebagai angka 32-bit" dalam JavaScript. Secara khusus, ia membuang semua kecuali 32 bit bagian bawah (karena ~operator bitwise hanya melihat bagian bawah 32 bit), yang identik dengan cara kerja overflow Java.

Jika Anda tidak memiliki itu, kode hash objek akan berbeda tergantung pada apakah itu dievaluasi di Jawa-tanah atau di tanah JavaScript (melalui kompilasi GWT).

yshavit
sumber
10
@harold Ini bukan hal GWT, ini hal JavaScript. Baru saja angka bekerja dalam bahasa itu.
yshavit
18
@yshavit Namun, ini bukan bagaimana angka bekerja di Jawa. Jika GWT tidak menyembunyikan fakta bahwa angka-angka diimplementasikan secara berbeda di JS dan pada JVM dari pengguna, maka memang itu adalah kompiler yang buruk.
valderman
8
@harold, yeah, ini JavaScript yang mengimplementasikan bilangan bulat tidak benar (sebenarnya tidak ada yang namanya bilangan bulat dalam JavaScript).
MikeTheLiar
8
@ Valderman Itu poin yang bagus. Menambahkan |0atau ~~terdengar seperti itu tidak akan sulit, meskipun saya tidak tahu apa yang akan terjadi pada kinerja (Anda harus menambahkannya di setiap langkah dari setiap ekspresi). Saya tidak tahu apa pertimbangan desainnya. Pertama, ketidakkonsistenan didokumentasikan pada halaman kompatibilitas GWT .
yshavit
6
hashCodeaneh karena sengaja pengadilan, atau bahkan mengharapkan, meluap terjadi. Satu-satunya tempat Anda dapat mengamati inkonsistensi adalah di mana Java int normal akan meluap, yang bukan masalah yang muncul di sebagian besar kode; hanya relevan dalam kasus aneh yang satu ini.
Louis Wasserman