การเปรียบเทียบค่า Long แบบบรรจุกล่อง 127 และ 128


111

ฉันต้องการเปรียบเทียบค่าLong object สองค่าโดยใช้ifเงื่อนไข เมื่อค่าเหล่านี้มีน้อยกว่า 128ในifสภาพที่ใช้งานได้อย่างถูกต้อง แต่เมื่อพวกเขามีค่ามากกว่าหรือเท่ากับ 128เปรียบเทียบล้มเหลว

ตัวอย่าง:

Long num1 = 127;
Long num2 = 127;

if (num1 == num2) {
    // Works ok
}

การเปรียบเทียบโค้ดด้านบนทำงานได้อย่างถูกต้อง แต่ล้มเหลวในโค้ดด้านล่าง:

Long num1 = 128;
Long num2 = 128;

if (num1 == num2) {
    // Does NOT work
}

ทำไมถึงมีปัญหาในการเปรียบเทียบยาวตัวแปรที่มีค่าสูงกว่า 127 ? หากชนิดข้อมูลตัวแปรถูกเปลี่ยนเป็นแบบดั้งเดิมแบบยาวการเปรียบเทียบจะใช้ได้กับทุกกรณี

คำตอบ:


212

TL; ดร

แคช Java บรรจุกล่องกรณีจำนวนเต็มจากไป-128 127เนื่องจากคุณกำลังใช้==เพื่อเปรียบเทียบการอ้างอิงอ็อบเจ็กต์แทนค่าเฉพาะอ็อบเจ็กต์ที่แคชเท่านั้นที่จะจับคู่ ทำงานกับlongค่าดั้งเดิมที่ไม่มีกล่องหรือใช้.equals()เพื่อเปรียบเทียบLongวัตถุของคุณ

เวอร์ชันยาว (เล่นสำนวนเจตนา)

เหตุใดจึงมีปัญหาในการเปรียบเทียบตัวแปร Long ที่มีค่ามากกว่า 127 หากชนิดข้อมูลของตัวแปรด้านบนเป็นแบบดั้งเดิม (แบบยาว) โค้ดจะใช้ได้กับทุกค่า

Java แคชจำนวนเต็มวัตถุกรณีจากช่วง -128 ถึง 127 ที่กล่าวว่า:

  • หากคุณตั้งค่าให้ตัวแปร N Long เป็นค่า127( แคช ) อินสแตนซ์อ็อบเจ็กต์เดียวกันจะถูกชี้โดยการอ้างอิงทั้งหมด (N ตัวแปร 1 อินสแตนซ์)
  • หากคุณตั้งค่าให้ตัวแปร N Long เป็นค่า128( ไม่ได้แคช ) คุณจะมีอินสแตนซ์วัตถุที่อ้างอิงทุกรายการ (ตัวแปร N, N อินสแตนซ์)

นั่นคือเหตุผลนี้:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

ผลลัพธ์นี้:

จริง
เท็จ

สำหรับ127Lคุ้มค่าเนื่องจากการอ้างอิงทั้งสอง (VAL1 และ VAL2) ชี้ไปที่วัตถุเช่นเดียวกันในหน่วยความจำ (แคช) trueก็จะส่งกลับ

ในทางกลับกันสำหรับค่า128เนื่องจากไม่มีอินสแตนซ์สำหรับแคชในหน่วยความจำจึงมีการสร้างอินสแตนซ์ใหม่สำหรับการกำหนดค่าใหม่ใด ๆ สำหรับค่าแบบบรรจุกล่องส่งผลให้มีอินสแตนซ์สองรายการที่แตกต่างกัน (ชี้โดย val3 และ val4) และส่งกลับfalseบน เปรียบเทียบระหว่างพวกเขา

สิ่งนี้เกิดขึ้นเพียงเพราะคุณกำลังเปรียบเทียบLong การอ้างอิงออบเจ็กต์สองรายการไม่ใช่longค่าดั้งเดิมกับตัว==ดำเนินการ หากไม่ใช่สำหรับกลไก Cache นี้การเปรียบเทียบเหล่านี้จะล้มเหลวเสมอดังนั้นปัญหาที่แท้จริงที่นี่คือการเปรียบเทียบค่าแบบบรรจุกล่องกับ==ตัวดำเนินการ

การเปลี่ยนตัวแปรเหล่านี้เป็นlongชนิดดั้งเดิมจะป้องกันไม่ให้สิ่งนี้เกิดขึ้น แต่ในกรณีที่คุณต้องการให้โค้ดของคุณใช้อLongอบเจ็กต์คุณสามารถทำการเปรียบเทียบเหล่านี้ได้อย่างปลอดภัยด้วยวิธีการต่อไปนี้:

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue());  // true
System.out.println((long)val3 == (long)val4);              // true

(จำเป็นต้องมีการตรวจสอบค่าว่างที่เหมาะสมแม้กระทั่งการหล่อ)

IMOเป็นความคิดที่ดีเสมอที่จะยึดติดกับ . equals ()วิธีการเมื่อจัดการกับการเปรียบเทียบวัตถุ

ลิงค์อ้างอิง:


15

Java เก็บค่าดั้งเดิมจาก-128 ถึง 127 เมื่อเราเปรียบเทียบLong object สองตัวjava ให้พิมพ์ cast it กับ primitive value แล้วเปรียบเทียบกัน แต่วัตถุ Long ที่สูงกว่า 127 จะไม่ได้รับประเภทวรรณะ Java เก็บผลผลิตโดย.valueOf ()วิธีการ

การแคชนี้ใช้ได้กับ Byte, Short, Long ตั้งแต่ -128 ถึง 127 สำหรับการแคชจำนวนเต็มใช้งานได้ตั้งแต่ -128 ถึง java.lang.Integer.IntegerCache.high หรือ 127 แล้วแต่จำนวนใดจะใหญ่กว่า (เราสามารถกำหนดค่าระดับบนสุดได้ไม่เกินค่า Integer ใด ควรได้รับแคชโดยใช้ java.lang.Integer.IntegerCache.high)

 For example:
    If we set java.lang.Integer.IntegerCache.high=500;
    then values from -128 to 500 will get cached and 

    Integer a=498;
    Integer b=499;
    System.out.println(a==b)

    Output will be "true".

วัตถุ Float และ Double จะไม่ถูกแคช

ตัวละครจะได้รับแคชจาก 0 ถึง 127

คุณกำลังเปรียบเทียบวัตถุสองชิ้น ดังนั้น==ตัวดำเนินการจะตรวจสอบความเท่าเทียมกันของการอ้างอิงวัตถุ มีวิธีทำดังต่อไปนี้

1) ประเภทโยนวัตถุทั้งสองให้เป็นค่าดั้งเดิมและเปรียบเทียบ

    (long)val3 == (long)val4

2) อ่านค่าของวัตถุและเปรียบเทียบ

    val3.longValue() == val4.longValue()

3) ใช้วิธีการเท่ากับ () ในการเปรียบเทียบวัตถุ

    val3.equals(val4);  

14

num1และnum2เป็นวัตถุทรงยาว คุณควรใช้equals()เพื่อเปรียบเทียบ ==การเปรียบเทียบอาจทำงานได้ในบางครั้งเนื่องจากวิธีดั้งเดิมของกล่อง JVM แต่ไม่ได้ขึ้นอยู่กับมัน

if (num1.equals(num1))
{
 //code
}

1
(ซึ่งจะดีกว่า) .longValue()หรือเปรียบเทียบค่าตอบแทนของ
Giulio Franco

4

การเปรียบเทียบ non-primitives (aka Objects) ใน Java โดย==เปรียบเทียบการอ้างอิงแทนค่า Longเป็นชั้นเรียนดังนั้นLongค่าเป็นวัตถุ

ปัญหาคือนักพัฒนา Java ต้องการให้คนใช้Longเหมือนที่เคยใช้longเพื่อให้เข้ากันได้ซึ่งนำไปสู่แนวคิดของการทำ autoboxing ซึ่งโดยพื้นฐานแล้วคุณลักษณะนั้นlong-values ​​จะเปลี่ยนเป็นLong-Objects และในทางกลับกันตามความจำเป็น พฤติกรรมของการทำกล่องอัตโนมัติไม่สามารถคาดเดาได้อย่างแน่นอนตลอดเวลาเนื่องจากไม่ได้ระบุไว้อย่างสมบูรณ์

ดังนั้นเพื่อความปลอดภัยและเพื่อให้ได้ผลลัพธ์ที่คาดเดาได้ควรใช้.equals()เพื่อเปรียบเทียบวัตถุเสมอและอย่าพึ่งพาการทำกล่องอัตโนมัติในกรณีนี้:

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.