2012-01-11 30 views
29

Trong Java, là có một cách để có được địa chỉ tham khảo, nóiCó cách nào để lấy địa chỉ tham chiếu không?

String s = "hello" 

Tôi có thể lấy địa chỉ của s bản thân, cũng có, tôi có thể lấy địa chỉ của đối tượng mà tham khảo đề cập đến?

+0

vui lòng chỉ định ý bạn là gì với địa chỉ? Địa chỉ trong bộ nhớ? Garbage collector-id? – yankee

+0

Tại sao bạn cần điều đó? – jarnbjo

+0

hoặc địa chỉ trong bộ nhớ hoặc thu gom rác id –

Trả lời

7

Không, bạn không thể. Ngay cả khi sử dụng Giao diện Bản địa Java (JNI), bạn chỉ có thể có được một xử lý mờ đối với cấu trúc dữ liệu, không phải là một con trỏ tới đối tượng JVM thực.

Tại sao bạn muốn một thứ như vậy? Nó không nhất thiết phải ở dạng bạn có thể sử dụng cho bất cứ thứ gì, dù sao, ngay cả từ mã gốc.

+0

Chỉ muốn đảm bảo một số tham chiếu giống nhau. –

+11

Nếu bạn muốn so sánh hai tham chiếu, bạn có thể làm điều đó với ==. Bạn không cần phải lấy địa chỉ của đối tượng. – jarnbjo

4

Không, bạn không thể. Đặc biệt không phải là Java có thể (và AFAIK làm) di chuyển các đối tượng xung quanh trong heap nếu nó là cần thiết cho bộ nhớ nén trong quá trình thu gom rác thải.

Tại sao bạn cần hoặc muốn điều này?

2

Địa chỉ thực tế có thể lấy được với sun.misc.Unsafe nhưng thực sự rất không an toàn. GC thường di chuyển các đối tượng.

+1

Liên kết tôi đăng trong bình luận của tôi cho Peter Lawry cho thấy cách bạn có thể làm điều đó, vì vậy bạn có thể giữ lại địa chỉ chính xác (nguyên nhân nếu bạn tạo các đối tượng sử dụng cấp phát bộ nhớ). bạn). Tôi đoán đó là cách BigMemory của Terracotta hoạt động. –

31

Bạn có thể nhận chỉ mục đối tượng bằng Không an toàn. Tùy thuộc vào cách JVM đang sử dụng bộ nhớ (địa chỉ 32 bit, chỉ mục 32 bit, chỉ mục 32 bit có bù đắp, địa chỉ 64 bit) có thể ảnh hưởng đến chỉ mục đối tượng hữu ích như thế nào.

Đây là chương trình giả sử bạn có chỉ mục 32 bit trong JVM 64 bit.

import sun.misc.Unsafe; 

import java.lang.reflect.Field; 
import java.util.Arrays; 
import java.util.Collections; 

public class OrderOfObjectsAfterGCMain { 
    static final Unsafe unsafe = getUnsafe(); 
    static final boolean is64bit = true; // auto detect if possible. 

    public static void main(String... args) { 
     Double[] ascending = new Double[16]; 
     for(int i=0;i<ascending.length;i++) 
      ascending[i] = (double) i; 

     Double[] descending = new Double[16]; 
     for(int i=descending.length-1; i>=0; i--) 
      descending[i] = (double) i; 

     Double[] shuffled = new Double[16]; 
     for(int i=0;i<shuffled.length;i++) 
      shuffled[i] = (double) i; 
     Collections.shuffle(Arrays.asList(shuffled)); 

     System.out.println("Before GC"); 
     printAddresses("ascending", ascending); 
     printAddresses("descending", descending); 
     printAddresses("shuffled", shuffled); 

     System.gc(); 
     System.out.println("\nAfter GC"); 
     printAddresses("ascending", ascending); 
     printAddresses("descending", descending); 
     printAddresses("shuffled", shuffled); 

     System.gc(); 
     System.out.println("\nAfter GC 2"); 
     printAddresses("ascending", ascending); 
     printAddresses("descending", descending); 
     printAddresses("shuffled", shuffled); 
    } 

    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(); 
    } 

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

Chạy trên bản cập nhật Java 6 26 (64 bit với nén oops) và Java 7. Lưu ý: địa chỉ và địa chỉ tương đối nằm trong hex.

Before GC 
ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18 
descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
shuffled: 0x782322ec0, +78, -30, +90, -c0, +18, +90, +a8, -30, -d8, +f0, -30, -90, +60, -48, +60 

After GC 
ascending: 0x686811590, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
descending: 0x686811410, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
shuffled: 0x686811290, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 

HOẶC đôi khi

Before GC 
ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18 
descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
shuffled: 0x782323028, -168, +150, -d8, -30, +60, +18, +30, +30, +18, -108, +30, -48, +78, +78, -30 

After GC 
ascending: 0x6868143c8, +4db0, +7120, -bd90, +bda8, -bd90, +4d40, +18, +18, -12710, +18, +80, +18, +ffa8, +220, +6b40 
descending: 0x68681d968, +18, +d0, +e0, -165d0, +a8, +fea8, +c110, -5230, -d658, +6bd0, +be10, +1b8, +75e0, -19f68, +19f80 
shuffled: 0x686823938, -129d8, +129f0, -17860, +4e88, +19fe8, -1ee58, +18, +18, +bb00, +6a78, -d648, -4e18, +4e40, +133e0, -c770 
+2

++ công việc tốt. Sẽ chỉ ra điều này từ một liên kết SO khác: http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe, nhưng bạn đã cho thấy cách làm điều đó với mã để thậm chí tốt hơn. –

+2

Đây là công cụ gọn gàng, nhưng độc giả nên cẩn thận để nhận ra rằng đây không phải là xách tay; lớp 'Unsafe' là một chi tiết triển khai không có giấy tờ của các JVM có nguồn gốc Sun. Mã này sẽ không hoạt động trên J9, JRockit, Dalvik, v.v. –

+0

@PeterLawrey Có giải thích chi tiết nào về điều 32 bit và 64 bit không? Tôi khá hứng thú với điều đó. – dawnstar

1

Đó là không thể trong Java để có được một địa chỉ tham chiếu của một đối tượng, như String của bạn. Địa chỉ tham chiếu của một đối tượng bị ẩn với người dùng, trong Java.

Trong C, bạn có thể làm điều này, thông qua khái niệm về con trỏ. Java có khái niệm tương tự, ở mức độ thấp, và đây là địa chỉ tham chiếu. Tham chiếu giống như một con trỏ C, nhưng nó không rõ ràng. Trong C, bạn có thể thực hiện thao tác tham chiếu con trỏ, thông qua *, nhưng trong Java, điều đó là không thể.

Tôi không thích nhiều ngôn ngữ C, cũng bởi vì con trỏ, theo tôi, không phải là một khái niệm dễ quản lý. Đây là một trong những lý do tôi thích Java, bởi vì các lập trình viên không cần phải lo lắng về con trỏ của một đối tượng.

Giống như @jarnbjo nói, bạn có thể kiểm tra, nếu một số tài liệu tham khảo tương tự, với một cú pháp như thế này:

String s = "hello"; 
String g = s; 
System.out.println("Are the reference addresses similar? "+(s==g)); 
g = "goodbye"; 
System.out.println("Are the reference addresses similar? "+(s==g)); 

Lưu ý rằng == kiểm tra sự bình đẳng của địa chỉ tham khảo. Nếu bạn muốn kiểm tra tính bình đẳng của giá trị của các chuỗi, hãy sử dụng phương thức equals().

Tôi đề nghị bạn đọc this câu hỏi SO, this trang Wikipedia và this trang.

3

Có, Bạn có thể làm điều đó với An toàn, Thông qua không trực tiếp. Đặt đối tượng hoặc cá thể tham chiếu vào một int [], điều đó là ok. long [] cũng ổn thôi.

@Test 
public void test1() throws Exception { 
    Unsafe unsafe = Util.unsafe; 
    int base = unsafe.arrayBaseOffset(int[].class); 
    int scale = unsafe.arrayIndexScale(int[].class); 
    int shift = 31 - Integer.numberOfLeadingZeros(scale); 
    System.out.printf("base: %s, scale %s, shift: %s\n", base, scale, shift); 
    base = unsafe.arrayBaseOffset(Object[].class); 
    scale = unsafe.arrayIndexScale(Object[].class); 
    shift = 31 - Integer.numberOfLeadingZeros(scale); 
    System.out.printf("base: %s, scale %s, shift: %s\n", base, scale, shift); 
    int[] ints = { 1, 2, 0 }; 
    String string = "abc"; 
    System.out.printf("string: id: %X, hash: %s\n", System.identityHashCode(string), string.hashCode()); 
    unsafe.putObject(ints, offset(2, shift, base), string); 
    System.out.printf("ints: %s, %X\n", Arrays.toString(ints), ints[2]); 
    Object o = unsafe.getObject(ints, offset(2, shift, base)); 
    System.out.printf("ints: %s\n", o); 
    assertSame(string, o); 

    Object[] oa = { 1, 2, string }; 
    o = unsafe.getObject(oa, offset(2, shift, base)); 
    assertSame(string, o); 
    int id = unsafe.getInt(oa, offset(2, shift, base)); 
    System.out.printf("id=%X\n", id); 
} 

public static long offset(int index, int shift, int base) { 
    return ((long) index << shift) + base; 
} 
+1

Các gói này thuộc loại nào? –

+0

sun.misc.Unsafe. hg openjdk.java.net. jdk \ src \ share \ classes \ sun \ misc \ Unsafe.java – qinxian

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