Java中如何获取对象(引用)地址?

上周有同学问,对象的hashcode是否就是它的地址?如何获取Java中一个对象的地址? 首先我们来看第一个问题——对象的hashcode是否是它的地址,这个问题的答案是这个取决于具体的实现,一般来说,它常常是对象的初始地址的整数表示。我们可以从JDK中Object类中hashcode()方法的注释看出来: 其中,重点是这句

* This is typically implemented by converting the internal * address of the object into an integer, but this implementation * technique is not required by the * Java™ programming language.

翻译成中文是,这个方法的典型实现是通过把对象的内部地址转为为整数,但是这种实现技术并不是Java编程语言所规定的。 为什么我还在最上面的回答加上一个初始地址呢?因为Java中的对象是JVM在管理,JVM会在她认为合适的时候对对象进行移动,比如,在某些需要整理内存碎片的GC算法下发生的GC。既然,对象的地址会变动,那么第二个问题还有意义么?对不起,确实没意义。但是我们仍然有权利知道我们想知道的一切,下面的代码展示了如何获取对象的地址,同时也对GC前后对象的地址进行了输出,便于比较。

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;

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

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

        System.gc();
        System.out.println("
After GC");
        printAddresses("ascending", ascending);


    }

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

created by 刘Sir

经验分享 程序员 微信小程序 职场和发展