2012-01-11 35 views
29

在Java中,有没有办法让参考地址,说有没有办法获得参考地址?

String s = "hello" 

我能得到S的地址本身,也可以我得到它的参考是指对象的地址?

+0

请指定您的地址是什么意思?在内存中的地址?垃圾收集器的ID? – yankee 2012-01-11 13:37:27

+0

你为什么需要这个? – jarnbjo 2012-01-11 13:37:56

+0

在内存中的地址或垃圾回收器ID – 2012-01-11 13:39:47

回答

7

不,你不能。即使使用Java本地接口(JNI),也只能获得数据结构的不透明句柄,而不是指向真正的JVM对象的指针。

你为什么要这样的事情?无论如何,即使使用本地代码,它也不一定会以任何形式使用。

+0

只是想确保一些参考是相同的。 – 2012-01-11 13:40:31

+11

如果你想比较两个引用,你可以用==来完成。您不需要获取对象的地址。 – jarnbjo 2012-01-11 13:45:14

4

不,你不能。特别是,如果垃圾收集期间需要内存压缩,Java可以(和AFAIK)在堆中移动对象。

为什么你甚至需要或想要这个?

2

其实地址可以用sun.misc.Unsafe得到,但它确实非常不安全。 GC经常移动物体。

+1

我在Peter Lawry的评论中发布的链接显示了你如何做到这一点,这样你就可以保留正确的地址(如果你使用内存分配创建对象,你可能在技术上可以从堆外部获得GC不会影响的地方您)。我猜这就是Terracotta的BigMemory的工作原理。 – 2012-01-11 13:58:29

31

您可以使用不安全的对象索引。取决于JVM如何使用内存(32位地址,32位索引,带偏移量的32位索引,64位地址)会影响对象索引的有用程度。

这是一个假设您在64位JVM中具有32位索引的程序。

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

运行在Java 6更新26(64位与压缩糟糕)和Java 7.注:地址和相对地址是十六进制的。

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 

或有时

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

++很好。是要从另一个SO链接指出这一点:http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe,但你展示了如何用代码做到这一点,甚至更好。 – 2012-01-11 13:54:10

+2

这是整洁的东西,但读者应该小心认识到这不是便携式的; “Unsafe”类是Sun派生的JVM的未公开的实现细节。此代码将无法在J9,JRockit,Dalvik等上工作。 – 2012-01-11 14:32:33

+0

@PeterLawrey有没有关于32位和64位的东西的详细解释?我对此非常感兴趣。 – dawnstar 2013-05-11 12:55:09

1

这是不可能在Java中得到一个对象的引用地址,喜欢你的字符串。 对象的引用地址以Java隐藏给用户。

在C中,你可以通过指针的概念来做到这一点。 Java有一个类似的概念,在低级别,这是参考地址。该引用就像一个C指针,但它并不明确。在C语言中,可以通过*执行指针引用的操作,但在Java中,这是不可能的。

我不太喜欢C语言,也因为根据我的指针,这不是一个简单的管理概念。这是我喜欢Java的原因之一,因为程序员不需要担心对象的指针。

像@jarnbjo说,你可以检查一下,如果一些引用是相似的,像这样的语法:

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

注意==检查参考地址的平等。如果您想检查字符串值的相等性,请使用equals()方法。

我建议您阅读this SO问题,this维基百科页面和this页面。

3

是的,你可以用不安全的方法做到这一点,虽然不是那么直接。 把对象或实例引用放入一个int [],没关系。 long []也应该很好。

@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

这些类的包是什么? – 2015-02-11 20:34:01

+0

sun.misc.Unsafe。 hg openjdk.java.net。 JDK的\ src \共享\类\太阳\杂项\ Unsafe.java – qinxian 2017-03-21 15:04:51

相关问题