回答
不,你不能。即使使用Java本地接口(JNI),也只能获得数据结构的不透明句柄,而不是指向真正的JVM对象的指针。
你为什么要这样的事情?无论如何,即使使用本地代码,它也不一定会以任何形式使用。
只是想确保一些参考是相同的。 – 2012-01-11 13:40:31
如果你想比较两个引用,你可以用==来完成。您不需要获取对象的地址。 – jarnbjo 2012-01-11 13:45:14
不,你不能。特别是,如果垃圾收集期间需要内存压缩,Java可以(和AFAIK)在堆中移动对象。
为什么你甚至需要或想要这个?
其实地址可以用sun.misc.Unsafe得到,但它确实非常不安全。 GC经常移动物体。
我在Peter Lawry的评论中发布的链接显示了你如何做到这一点,这样你就可以保留正确的地址(如果你使用内存分配创建对象,你可能在技术上可以从堆外部获得GC不会影响的地方您)。我猜这就是Terracotta的BigMemory的工作原理。 – 2012-01-11 13:58:29
您可以使用不安全的对象索引。取决于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
++很好。是要从另一个SO链接指出这一点:http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe,但你展示了如何用代码做到这一点,甚至更好。 – 2012-01-11 13:54:10
这是整洁的东西,但读者应该小心认识到这不是便携式的; “Unsafe”类是Sun派生的JVM的未公开的实现细节。此代码将无法在J9,JRockit,Dalvik等上工作。 – 2012-01-11 14:32:33
@PeterLawrey有没有关于32位和64位的东西的详细解释?我对此非常感兴趣。 – dawnstar 2013-05-11 12:55:09
这是不可能在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()
方法。
是的,你可以用不安全的方法做到这一点,虽然不是那么直接。 把对象或实例引用放入一个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;
}
这些类的包是什么? – 2015-02-11 20:34:01
sun.misc.Unsafe。 hg openjdk.java.net。 JDK的\ src \共享\类\太阳\杂项\ Unsafe.java – qinxian 2017-03-21 15:04:51
- 1. 有没有办法得到寄存器的地址?
- 2. ASMX Web服务 - 没有获得参考
- 3. 有没有办法获得与Windows Live ID关联的电子邮件地址?
- 4. 有没有办法获得维基百科网址的最终目的地?
- 5. 有没有什么办法可以在Rust中获得`struct`的地址?
- 6. 有没有办法从FutureTask获得Callable?
- 7. ShareKit - SHKFacebook:有没有办法获得authorization_token?
- 8. 有没有办法从Bing SOAP Search Service获取地址?
- 9. 有没有办法在Common Lisp中获取可变地址?
- 10. 有没有办法获得函数参数的类型?
- 11. 有没有办法获得域名的网站地图?
- 12. 有没有办法按地点获得facebook的公开帖子?
- 13. Netsuite:有没有办法拥有专门的装运地址和帐单地址?
- 14. 有没有什么办法让for_each参考?
- 15. 有没有办法在ActionLink中考虑MapRoute中的URL参数?
- 16. 有没有办法看到名称空间参考?
- 17. 有没有办法在Visual Studio中找到dll参考?
- 18. 有没有办法让ASP.NET 5依赖注入解决没有参考的DbContext?
- 19. 有没有办法告诉浏览器加入地址栏以外的地址?
- 20. 有没有办法获得传递给方法的参数数组?
- 21. 有没有办法根据地址生成位置的坐标?
- 22. 有没有办法间接输入文本到地址栏?
- 23. 有没有办法用C ping特定的IP地址?
- 24. 有没有办法使用EMail地址作为用户名?
- 25. 有没有办法找出IP地址是否属于iPhone?
- 26. PHP:有没有办法改变请求地址?
- 27. html5获取和使用坐标获得地址没有地图
- 28. 有没有办法从Cocoa中给定的URL获取IP地址?
- 29. 有没有办法根据手机号码从手机获取WAN IP地址?
- 30. 有没有办法从JMS消息中获取起始IP地址?
请指定您的地址是什么意思?在内存中的地址?垃圾收集器的ID? – yankee 2012-01-11 13:37:27
你为什么需要这个? – jarnbjo 2012-01-11 13:37:56
在内存中的地址或垃圾回收器ID – 2012-01-11 13:39:47