我可以使用sun.misc.Unsafe覆盖对象吗?

9
如果两个对象是同一类的实例,它们的大小相同,那么我能否使用sun.misc.Unsafe来用一个对象覆盖另一个对象?
编辑: 我的意思是“覆盖”第一个对象,然后用第二个对象填充内存。这可能吗?

“Override”是什么意思?请提供更多上下文。 - Jon Skeet
1
我猜他想要一个Java版本的Smalltalk的become: - Tom Anderson
1个回答

9
“覆盖”指的是“删除”第一个对象,并用第二个对象填充内存。这可能吗?
是和否。
是 - 如果您使用Unsafe分配一些内存并写入long,然后在其中写入另一个long(例如),那么是的,您已经删除了第一个对象并用第二个对象填充了内存。这类似于您可以使用ByteBuffer做的事情。当然,long是原始类型,所以这可能不是您所指的“对象”。
Java允许这样做,因为它对分配的内存具有控制权。
否 - Java使用对象的引用,并仅提供对这些对象的引用。此外,它倾向于在内存中移动对象(即进行垃圾回收)。
如果您想获取“物理地址”并将内存内容从一个对象地址移动到另一个对象地址,那是不可能的。此外,您实际上无法“删除”对象,因为代码中其他地方可能引用了它。
但是,始终有可能使引用A指向另一个对象B而不是对象A,例如 A = objectB;。您甚至可以使用Unsafe.compareAndSwapObject(...)使其原子化。
解决方法 - 现在,假设引用A1、A2、A3都指向同一对象A。如果您希望它们全部突然指向对象B,则不能使用Unsafe.compareAndSwapObject(...),因为只有A1会指向对象B,而A2和A3仍将指向对象A。这不是原子的。
有一个解决方法:
public class AtomicReferenceChange {

    public static Object myReference = new Object();

    public static void changeObject(Object newObject) {
        myReference = newObject;
    }

    public static void main(String[] args) {

        System.out.println(AtomicReferenceChange.myReference);
        AtomicReferenceChange.changeObject("333");
        System.out.println(AtomicReferenceChange.myReference);

    }

}

不要多次引用同一对象,您可以定义一个公共静态引用,并让您的代码在所有地方使用AtomicReferenceChange.myReference。如果您想以原子方式更改引用的对象,请使用静态方法changeObject(...)


2
扩展这个解决方案,如果您可以控制相关的类,那么您可能可以通过使用代理模式(http://en.wikipedia.org/wiki/Proxy_pattern)更优雅地解决此问题。代理类将提供实际类的所有方法,但它只会将它们委派给一个包装对象。客户端无需知道他们是否在使用代理,并通过交换包装对象,您可以使它们看起来好像正在使用的对象已被替换。 - Medo42
非常正确,当您需要同时修改多个引用时,代理模式肯定比多个静态变量更合适。在代理类中修改它更容易... - Jérôme Verstrynge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接