ที่อยู่หน่วยความจำของตัวแปรใน Java


139

โปรดดูภาพด้านล่าง เมื่อเราสร้างวัตถุใน java ด้วยnewคำหลักเราจะได้รับที่อยู่หน่วยความจำจากระบบปฏิบัติการ

เมื่อเราเขียนout.println(objName)เราจะเห็นสตริง "พิเศษ" เป็นผลลัพธ์ คำถามของฉันคือ:

  1. ผลลัพธ์นี้คืออะไร
  2. หากเป็นที่อยู่หน่วยความจำที่ระบบปฏิบัติการมอบให้เรา:

    a) ฉันจะแปลงสตริงนี้เป็นไบนารีได้อย่างไร

    b) ฉันจะรับที่อยู่ตัวแปรจำนวนเต็มหนึ่งตัวได้อย่างไร

ข้อความแสดงแทน


5
ดีฉันไม่ได้มีสิทธิออกเสียงลงเนื่องจากคำถามคือพอที่ชัดเจนเพียงข้อเสนอแนะว่าคุณควรจะได้ทำให้มันในข้อความเพื่อให้ประชาชนสามารถค้นหามัน
phunehehe

2
ใช้ sun.misc.Unsafe เป็นไปได้ที่จะได้รับที่อยู่ของวัตถุ java สำหรับรายการโปรแกรมอ้างอิง: javapapers.com/core-java/address-of-a-java-object
Joseph Kulandai

ค่าที่แหลมคือการแสดงเลขฐานสิบหกของ hashcode ของวัตถุ a1 & a2
Naveen

คำตอบ:


166

นั่นคือชื่อคลาสและSystem.identityHashCode ()คั่นด้วยอักขระ '@' รหัสแฮชรหัสประจำตัวหมายถึงอะไรเฉพาะการติดตั้ง มักจะเป็นที่อยู่หน่วยความจำเริ่มต้นของวัตถุ แต่วัตถุสามารถเคลื่อนย้ายในหน่วยความจำโดย VM เมื่อเวลาผ่าน ดังนั้น (สั้น ๆ ) คุณไม่สามารถเชื่อได้ว่ามันเป็นอะไร

การรับที่อยู่หน่วยความจำของตัวแปรนั้นไม่มีความหมายภายใน Java เนื่องจาก JVM มีอิสระในการใช้งานวัตถุและย้ายตามที่เหมาะสม (วัตถุของคุณอาจ / จะเคลื่อนที่ไปรอบ ๆ ระหว่างการรวบรวมขยะ ฯลฯ )

Integer.toBinaryString ()จะให้จำนวนเต็มในรูปแบบไบนารี


33
อีกจุดที่น่าสนใจคือรหัสแฮชข้อมูลเฉพาะตัวไม่ได้รับประกันว่าจะไม่ซ้ำกัน ตัวอย่างเช่นใน JVM แบบ 64 บิตมีรหัสแฮชรหัสประจำตัว 2 ^ 32แต่ 2 ^ 64 อยู่หน่วยความจำ
Alex Jasmin

11
ที่จริงแล้วรหัสแฮชของรหัสประจำตัว ไม่สามารถเปลี่ยนแปลงได้มิฉะนั้นสัญญาของ hashCode () จะถูกละเมิด
Matt McHenry

1
ฉันใช้สิ่งนี้ในการบันทึก / ตรวจแก้จุดบกพร่องเพื่อระบุในบันทึกเมื่อวัตถุชี้ไปที่วัตถุเดียวกันแทนที่จะเป็นวัตถุที่เทียบเท่ากัน สำหรับวัตถุประสงค์เหล่านี้identityHashcodeไม่ใช่ความหมายมันไม่เข้าใจผิดได้ :)
เลื่อน

@BrianAgnew: ฉันต้องการทราบ -> ทำไมวัตถุสองรายการจึงมีแฮชโค้ดเดียวกัน ฉันสับสนเพราะฉันได้เรียนรู้ใน c หรือ c ++ ทุกตัวแปรหรือวัตถุมีตำแหน่งหน่วยความจำที่แตกต่างกัน จากนั้นใน java วิธีสามารถระบุหรือแยกความแตกต่างของวัตถุทั้งสองด้วย hashCode เดียวกัน
Ved Prakash

1
@VedPrakash วัตถุ hashcode ช่วยให้วัตถุถูกเก็บไว้ในคอลเลกชันที่ถูกแฮช หากคุณต้องการแยกความแตกต่างของสองวัตถุคุณสามารถใช้ความเท่าเทียมกันในการอ้างอิงได้
Brian Agnew

36

เป็นไปได้โดยใช้sun.misc.Unsafe: ดูคำตอบที่ยอดเยี่ยมนี้จาก @Peter Lawrey -> มีวิธีรับที่อยู่อ้างอิงหรือไม่

การใช้รหัสสำหรับ printAddresses ():

    public static void printAddresses(String label, Object... objects) {
    System.out.print(label + ": 0x");
    long last = 0;
    int offset = unsafe.arrayBaseOffset(objects.getClass());
    int scale = unsafe.arrayIndexScale(objects.getClass());
    switch (scale) {
    case 4:
        long factor = is64bit ? 8 : 1;
        final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
        System.out.print(Long.toHexString(i1));
        last = i1;
        for (int i = 1; i < objects.length; i++) {
            final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
            if (i2 > last)
                System.out.print(", +" + Long.toHexString(i2 - last));
            else
                System.out.print(", -" + Long.toHexString( last - i2));
            last = i2;
        }
        break;
    case 8:
        throw new AssertionError("Not supported");
    }
    System.out.println();
}

ฉันตั้งค่าการทดสอบนี้:

    //hashcode
    System.out.println("Hashcode :       "+myObject.hashCode());
    System.out.println("Hashcode :       "+System.identityHashCode(myObject));
    System.out.println("Hashcode (HEX) : "+Integer.toHexString(myObject.hashCode()));

    //toString
    System.out.println("toString :       "+String.valueOf(myObject));

    printAddresses("Address", myObject);

นี่คือผลลัพธ์:

Hashcode :       125665513
Hashcode :       125665513
Hashcode (HEX) : 77d80e9
toString :       java.lang.Object@77d80e9
Address: 0x7aae62270

สรุป:

  • hashcode! = ที่อยู่
  • toString = class @ HEX (hashcode)

13

นั่นคือผลลัพธ์ของการใช้ "toString ()" ของ Object หากคลาสของคุณแทนที่ toString () คลาสนั้นจะพิมพ์บางอย่างที่แตกต่างออกไปโดยสิ้นเชิง


6

นี่ไม่ใช่ที่อยู่หน่วยความจำ นี่คือclassname @ hashcode

ที่ไหน

classname = ชื่อเต็มหรือชื่อสัมบูรณ์ (เช่นชื่อแพ็กเกจตามด้วยชื่อคลาส)

hashcode = รูปแบบเลขฐานสิบหก (System.identityHashCode (obj) หรือ obj.hashCode () จะให้แฮชโค้ดในรูปแบบทศนิยม)


4

เช่นเดียวกับ Sunil กล่าวว่านี่ไม่ใช่ที่อยู่หน่วยความจำนี่เป็นเพียงรหัสแฮช

หากต้องการรับเนื้อหา @ เดียวกันคุณสามารถ:

ถ้า hashCode ไม่ถูกเขียนทับในคลาสนั้น:

"@" + Integer.toHexString(obj.hashCode())

หาก hashCode ถูกแทนที่คุณจะได้รับค่าดั้งเดิมด้วย:

"@" + Integer.toHexString(System.identityHashCode(obj)) 

ซึ่งมักจะสับสนกับที่อยู่หน่วยความจำเพราะถ้าคุณไม่ได้แทนที่ hashCode () ที่อยู่หน่วยความจำจะใช้ในการคำนวณแฮช


1

สิ่งที่คุณได้รับคือผลลัพธ์ของเมธอด toString () ของคลาส Object หรือ identityHashCode () ที่แม่นยำยิ่งขึ้นเมื่อ uzay95 ชี้ให้เห็น

"เมื่อเราสร้างวัตถุใน java ด้วยคำหลักใหม่เราได้รับที่อยู่หน่วยความจำจากระบบปฏิบัติการ"

สิ่งสำคัญคือต้องตระหนักว่าทุกสิ่งที่คุณทำใน Java ได้รับการจัดการโดย Java Virtual Machine เป็น JVM ที่ให้ข้อมูลนี้ สิ่งที่เกิดขึ้นจริงใน RAM ของระบบปฏิบัติการโฮสต์นั้นขึ้นอยู่กับการนำ JRE มาใช้ทั้งหมด



0

ใน Java เมื่อคุณทำวัตถุจากชั้นเรียนเช่นPerson p = new Person();, เป็นจริงที่อยู่ของสถานหน่วยความจำที่จะชี้ไปที่ประเภทของpPerson

เมื่อใช้ statemenet เพื่อพิมพ์pคุณจะเห็นที่อยู่ newคำสำคัญที่ทำให้สถานที่ตั้งหน่วยความจำใหม่ที่มีทั้งหมดเช่นตัวแปรและวิธีการซึ่งรวมอยู่ในclass Personและpเป็นชี้ตัวแปรอ้างอิงถึงที่ตั้งของหน่วยความจำที่


ในรูปภาพของคุณ a1 และ a2 เป็นที่อยู่หน่วยความจำสองแบบที่แตกต่างกันนั่นคือเหตุผลที่อยู่เบื้องหลังการรับค่าที่แตกต่างกันสองค่า
Panduka Wedisinghe
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.