ความหมายของ double tilde (~~) ใน Java คืออะไร?


192

เมื่อเรียกดูซอร์สโค้ดของ Guava ฉันพบรหัสต่อไปนี้ (ส่วนหนึ่งของการนำไปใช้hashCodeสำหรับคลาสภายใน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;

ทั้งสองadjustและhashมีints จากสิ่งที่ฉันรู้เกี่ยวกับ Java ~หมายถึงการปฏิเสธ bitwise ดังนั้นadjust = ~~adjustและhash = ~~hashควรปล่อยให้ตัวแปรไม่เปลี่ยนแปลง ใช้การทดสอบขนาดเล็ก (แน่นอนว่ามีการเปิดใช้งานการยืนยัน)

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

ยืนยันสิ่งนี้ สมมติว่าพวกฝรั่งรู้ว่าพวกเขากำลังทำอะไรต้องมีเหตุผลให้พวกเขาทำเช่นนี้ คำถามคืออะไร

แก้ไขตามที่ระบุไว้ในความคิดเห็นการทดสอบข้างต้นไม่รวมกรณีที่iเท่าInteger.MAX_VALUEกัน เนื่องจากi <= Integer.MAX_VALUEเป็นจริงเสมอเราจะต้องตรวจสอบกรณีนอกวงเพื่อป้องกันไม่ให้วนซ้ำตลอดไป อย่างไรก็ตามสาย

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

ให้คำเตือนคอมไพเลอร์ "การเปรียบเทียบนิพจน์ที่เหมือนกัน" ซึ่งเล็บมันสวยมาก


42
@dr_andonuts Guava เป็นห้องสมุดมาตรฐานที่น่าสนใจที่จะรวมไว้ในโครงการทุกวันนี้ - ฉันคิดว่าคำแนะนำในการวิ่งหนีไกลถูกใส่ผิดที่
yshavit

4
Integer.MAX_VALUEยืนยันไม่ได้ตรวจสอบกรณีที่ขอบ -(-Integer.MIN_VALUE) != Integer.MIN_VALUEตรงกันข้ามกับ
Franky

3
@ Franky สิ่งที่ maaartinus พูด -Integer.MIN_VALUEล้อมรอบไปInteger.MIN_VALUEดังนั้นปฏิเสธว่าอีกครั้งเพียงสร้างInteger.MIN_VALUEอีกครั้ง

2
@maaartinus @hvd ขอบคุณที่ชี้ให้เห็น ตอนนี้ฉันจำ-x = (~x) + 1ได้
Franky

7
@dr_andonuts กำลังหมุนรอบ ทำไมต้องหนีจากสิ่งที่คุณไม่เข้าใจ นี่คือสิ่งที่ StackOverflow ใช้สำหรับ: เพื่อช่วยคุณเรียนรู้
Jared Burrows

คำตอบ:


245

ใน Java มันไม่มีความหมายอะไร

แต่ความคิดเห็นนั้นบอกว่าบรรทัดนั้นมีไว้สำหรับ GWT ซึ่งเป็นวิธีในการคอมไพล์ Java กับ JavaScript

ในจาวาสคริปต์จำนวนเต็มเป็นจำนวนเต็มสองเท่าที่ทำหน้าที่เป็นจำนวนเต็ม พวกเขามีค่าสูงสุด 2 ^ 53 เช่น แต่ตัวดำเนินการระดับบิตจะปฏิบัติกับตัวเลขราวกับว่าพวกเขาเป็นแบบ 32 บิตซึ่งเป็นสิ่งที่คุณต้องการในรหัสนี้ กล่าวอีกนัยหนึ่ง~~hashว่า "ถือว่าhashเป็นหมายเลข 32 บิต" ใน JavaScript โดยเฉพาะจะละทิ้งทั้งหมดยกเว้น 32 บิตด้านล่าง (เนื่องจากตัว~ดำเนินการระดับบิตจะดูที่ 32 บิตด้านล่างเท่านั้น) ซึ่งเหมือนกับการทำงานของโอเวอร์โฟลว์ของ Java

หากคุณไม่มีรหัสแฮชของวัตถุจะแตกต่างกันไปขึ้นอยู่กับว่ามันถูกประเมินใน Java-land หรือใน JavaScript ดินแดน (ผ่านการรวบรวม GWT)


10
@harold มันไม่ใช่ GWT มันเป็นของ JavaScript นั่นเป็นเพียงตัวเลขในภาษานั้น
yshavit

18
@yshavit อย่างไรก็ตามไม่ใช่ตัวเลขที่ทำงานใน Java หาก GWT ไม่ซ่อนความจริงที่ว่าตัวเลขถูกนำไปใช้ใน JS และ JVM แตกต่างจากผู้ใช้แสดงว่ามันเป็นคอมไพเลอร์ที่ไม่ดีอย่างแน่นอน
valderman

8
@harold ใช่มันเป็นจาวาสคริปต์ที่ใช้จำนวนเต็มไม่ถูกต้อง (อันที่จริงไม่มีสิ่งเช่นประเภทจำนวนเต็มใน JavaScript)
MikeTheLiar

8
@ valderman นั่นเป็นจุดที่ดี การเพิ่ม|0หรือ~~ฟังดูเหมือนว่ามันจะไม่ยาก แต่ฉันไม่รู้ว่าการแสดงที่ยอดเยี่ยมจะเป็นอย่างไร (คุณต้องเพิ่มทุกขั้นตอนของทุกการแสดงออก) ฉันไม่รู้ว่าสิ่งที่ต้องพิจารณาในการออกแบบคืออะไร FWIW, ความไม่สอดคล้องกันเป็นเอกสารในหน้าความเข้ากันได้ของ GWT
yshavit

6
hashCodeเป็นเรื่องแปลกที่ศาลจะจงใจหรือคาดการณ์ว่าจะเกิดเหตุการณ์ล้น ที่เดียวที่คุณสามารถสังเกตเห็นความไม่ลงรอยกันคือที่ซึ่ง Java int ปกติจะล้นซึ่งไม่ใช่ปัญหาที่เกิดขึ้นในโค้ดส่วนใหญ่ มันมีความเกี่ยวข้องในกรณีแปลก ๆ นี้
Louis Wasserman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.