2016-04-02 17 views
9

Phương thứcObject là duy nhất ở chỗ nó có vẻ là nơi duy nhất trong Java có thể xem được địa chỉ bộ nhớ. Làm thế nào để Object làm điều này?Object.toString() lấy "địa chỉ bộ nhớ" như thế nào và bắt chước nó như thế nào

Tôi muốn biết để tôi có thể bắt chước việc triển khai trong một lớp học của riêng tôi. Tôi không thể sử dụng super.toString() vì tôi đang mở rộng một lớp ghi đè toString rồi.

Cập nhật: Những tiền đề của câu hỏi của tôi yêu cầu cho địa chỉ bộ nhớ, nhưng câu trả lời đã chỉ ra rằng tiền đề này là không chính xác, vì vậy những gì tôi đang thực sự yêu cầu là: như thế nào Object.toString() trở lại những gì nó làm, và làm thế nào tôi có thể bắt chước nó?

+2

Bạn đã thử kiểm tra mã nguồn của lớp đối tượng – Panther

+0

Câu hỏi bắt buộc: tại sao bạn muốn làm điều đó? – fge

+1

Hãy xem tài liệu API. Đó không phải là địa chỉ bộ nhớ. Và có một cách để có được giống nhau mà không sử dụng 'toString()'. –

Trả lời

13

Đây không phải là địa chỉ bộ nhớ, là hashCode(). Xem thêm Object.toString() mà nói (một phần)

Phương pháp toString cho lớp Object trả về một chuỗi gồm tên của lớp trong đó đối tượng là một thể hiện, nhân vật ở-dấu @, và thập lục phân unsigned biểu diễn mã băm của đối tượng. Nói cách khác, phương pháp này trả về một chuỗi tương đương với giá trị của:

getClass().getName() + '@' + Integer.toHexString(hashCode()) 

Object.hashCode() nói (Điều này thường được thực hiện bằng cách chuyển đổi địa chỉ nội bộ của đối tượng vào một số nguyên, nhưng kỹ thuật thực hiện này là không yêu cầu bởi ngôn ngữ lập trình Java ™.) do đó, không phải yêu cầu là địa chỉ bộ nhớ và nếu được sử dụng, chỉ hiển thị cho việc triển khai nội bộ (bản địa) Object.

+0

Câu trả lời này là hữu ích nhất của câu trả lời, vì vậy tôi chọn nó ngay cả khi các câu trả lời khác cũng rất hữu ích (chẳng hạn như tôi có thể sử dụng 'System.identityHashCode') – 4castle

9

Không. Những gì nó nhận được là mã băm, không phải là địa chỉ bộ nhớ, và mã băm không có kết nối cần thiết đến địa chỉ bộ nhớ. (Có thể trong một số triển khai.)

Trong triển khai cơ sở, đó là System.identityHashCode, mặc dù nó vẫn không có mối quan hệ với địa chỉ bộ nhớ.

+1

hashCode là một số ngẫu nhiên trong HotSpot (theo mặc định) – ZhekaKozlov

+0

Vậy làm cách nào tôi có thể bắt chước việc triển khai đối tượng ' .toString() '? – 4castle

+2

@ 4castle thực hiện toàn bộ là 'getClass(). GetName() + '@' + Integer.toHexString (hashCode())'. Đó là toàn bộ việc thực hiện. Nhưng điều đó không liên quan gì đến địa chỉ bộ nhớ. –

0

Nếu bạn có thể tìm thấy định nghĩa này toString() trong Object Lớp. Bạn sẽ tìm thấy điều này.

getClass().getName() + '@' + Integer.toHexString(hashCode()) //returns [email protected] 

gì nó được là hash-code, không phải là địa chỉ bộ nhớ (Theo Louis Wasserman), và mã băm không có kết nối cần thiết đến địa chỉ bộ nhớ.

bạn nên ghi đè số này toString() cho mỗi lớp mà bạn đã khai báo trong Dự án của mình theo nhu cầu của bạn.

10

Phương thức toString của đối tượng là duy nhất ở chỗ nó có vẻ là nơi duy nhất trong Java nơi địa chỉ bộ nhớ có thể xem được. Object làm như thế nào?

Địa chỉ không nhận được địa chỉ, trong JVM HotSpot, nó nhận được mã băm 31 bit được tạo ngẫu nhiên được lưu trữ trong tiêu đề của đối tượng.Điều này phải được lưu trữ bởi vì;

  • mã băm không thể thay đổi ngay cả khi đối tượng được di chuyển và có địa chỉ mới.
  • địa chỉ không đủ ngẫu nhiên. 8 bit thấp hơn của địa chỉ luôn là 0. Sau mỗi GC, đối tượng đầu tiên được tạo luôn giống nhau.
  • địa chỉ có thể là 64 bit.

LÀM TRY NÀY TẠI NHÀ, KHÔNG THÍCH HỢP CHO CÔNG VIỆC !!

Bạn có thể nhận/đặt hashCode() sử dụng Unsafe

static final Unsafe UNSAFE; 

static { 
    try { 
     Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); 
     theUnsafe.setAccessible(true); 
     UNSAFE = (Unsafe) theUnsafe.get(null); 
    } catch (Exception e) { 
     throw new AssertionError(e); 
    } 
} 

public static void setIdentityHashCode(Object o, int code) { 
    UNSAFE.putInt(o, 1l, code & 0x7FFF_FFF); 
} 

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { 
    Double d = 1.0; 
    Double d2 = 1.0; 
    setIdentityHashCode(d, 1); 
    setIdentityHashCode(d2, 1); 
    System.out.println("d: "+d+" System.identityHashCode(d): "+System.identityHashCode(d)); 
    System.out.println("d2: "+d2+" System.identityHashCode(d2): "+System.identityHashCode(d2)); 
    System.out.println("d == d2: " + (d == d2)); 
} 

in

d: 1.0 System.identityHashCode(d): 1 
d2: 1.0 System.identityHashCode(d2): 1 
d == d2: false 

Bạn có thể lấy địa chỉ từ các giá trị tham khảo miễn là bạn biết làm thế nào bộ nhớ đã được dịch. Trong trường hợp đơn giản nhất, (nơi bạn có tham chiếu 64 bit) tham chiếu chưa được dịch và địa chỉ là giá trị được lưu trữ trong tham chiếu.

Nếu bạn chạy trên một JVM 64-bit với -XX:-UseCompressedOops

// This only works if a GC doesn't move the object while attempting to access it. 
static final Unsafe UNSAFE; 

static { 
    try { 
     Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); 
     theUnsafe.setAccessible(true); 
     UNSAFE = (Unsafe) theUnsafe.get(null); 
    } catch (Exception e) { 
     throw new AssertionError(e); 
    } 
} 

// run with: -ea -XX:-UseCompressedOops 
public static void main(String[] args) { 
    Object i = 0x12345678; 
    System.out.printf("indentityHashCode = %08x%n", System.identityHashCode(i)); 

    Object[] obj = { i }; 
    assert Unsafe.ARRAY_OBJECT_INDEX_SCALE == 8; // 8 bytes per reference. 
    long address = UNSAFE.getLong(obj, (long) Unsafe.ARRAY_OBJECT_BASE_OFFSET); 
    System.out.printf("%x%n", address); 
    for (int j=0;j<24;j++) 
     System.out.printf("%02x ", UNSAFE.getByte(address + j) & 0xFF); 
    System.out.println(); 
    // now some really scary sh!t 
    UNSAFE.putLong(i, 8L, UNSAFE.getLong(0L, 8L)); 
    System.out.printf("`i` is now a %s and is %x%n", i.getClass(), i); 
} 

in

indentityHashCode = 5a07e868 
7fbf41cb8560 
01 68 e8 07 5a 00 00 00 48 33 3f b9 b9 7f 00 00 78 56 34 12 00 00 00 00 
    ^^hashCode^   ^class address^  ^int value^ 
`i` is now a class java.lang.Long and is 12345678 
+2

Đừng nói điều này với mọi người, thực sự sẽ thử: D – noctarius

+0

@noctarius đã thêm cảnh báo NSFW. –

+1

* thích * :-) – noctarius

0

Đây không phải là một kẽ hở để có được một tổ chức của một địa chỉ bộ nhớ bởi vì tất cả các bạn nhận được là một mã băm được tạo ngẫu nhiên 31 bit trong tiêu đề của đối tượng. Nó không cung cấp bất kỳ cách nào thực sự có được một tổ chức của một địa chỉ bộ nhớ thực.

Các vấn đề liên quan