Java:如何像C++一样存储和检索内存地址

4

我来自C++背景。在C++中,我可以将刚刚使用new关键字分配的内存地址存储在全局数组中,并稍后重新使用它。例如,假设我有两个类X、Y,并创建了两个对象x、y。全局数组StoreAddresses[2]定义如下:

 uint32_t StoreAddresses[2];

I write:

 X * x = new X();
 Y * y = new Y();
 StoreAdresses[0] = (uint32t *) x; //for example, 0x12345678
 StoreAdresses[1] = (uint32t *) y; //for example, 0x12345698

在我的程序中的任何地方,我都可以通过调用以下代码来检索内存中写入的数据:

 X * stored_x = (X*)StoreAdresses[0];
 Y * stored_y = (Y*)StoreAdresses[1];

我应该如何在Java中实现这个? 感谢您的帮助!


1
Java和C/C++之间的主要区别之一是Java限制了程序员使用和滥用内存的能力。我想你可以使用字节数组来模拟这个过程(或者像Peter Lawrey所说的那样使用unsafe——给他一个赞),但更好的方法是学习Java的方式,并根据其优点而不是缺点来调整你的编码。 - Hovercraft Full Of Eels
同意@HovercraftFullOfEels的观点 - 要实现您似乎想要做的事情,您应该将XY的引用存储在静态字段中,而不是在内存地址上胡闹。 - Chii
真正的问题是:你为什么想要这样做? - Joeri Hendrickx
我敢打赌你需要的是一对大字节数组来进行直接字节操作。如果您不需要直接字节操作,请不要访问内存!访问您的对象!在Java中,您始终操纵引用。因此,编写X x = new X(); x.doThis()等同于C++中的X* x = new X(); x->doThis()。始终考虑对象指针和箭头访问。 - helios
谢谢你们的发帖。我会在下面回复彼得的帖子。我已经被吓到不再使用Unsafe了。 - goseib
4个回答

7
您可以使用Unsafe在Java中完成此操作。但这是一个非常糟糕的想法。这是因为对象的地址可以随时更改(通过GC)。如果您像这样存储地址并稍后使用它,它可能不再有效,甚至会使应用程序崩溃。如果GC认为对象没有强引用,它可能会清理该对象。当您尝试再次引用该对象时,它可能不再在JVM中。
地址的大小可以根据启动JVM的方式而变化。64位JVM通常使用32位引用(这可能会让从C ++转换的人感到惊讶)。您可以使用Unsafe.ADDRESS_SIZE获得这个大小。
我只会使用Unsafe来查看地址以了解对象在缓存中的布局方式。(这并不是很有用,因为您对此几乎无能为力 :()
很可能您正在尝试的任何事情都可以用更好的方法完成。您能否给我们更多细节?

你好,彼得。感谢你详细的回答。我之所以这么费劲地去做,是因为我在使用继承时犯了一个简单的错误...我有一个基类和4个子类。尽管我在基类中声明了我的原始公共对象,但我在其中一个子类中错误地进行了new操作。因此,在所有其他类中引用为空:(这就是我想到C++技巧的原因。现在我已经在基类中定义它,问题解决了!顺便说一句,C++内存操作在我的商业应用程序中在不同的架构中完美运行,没有缺陷。再次感谢你的帮助! - goseib
它在C++中有效是因为在使用指针时,它们不会被更改。 - Peter Lawrey

2

Peter说的是正确的。我想补充一点,你需要开始用Java术语来思考,而不是C++术语。

了解Java可能会帮助你,X x = new X();在Java中几乎完全等同于C++中的X* x = new X();


嗨Mike,我确实知道所有这些东西。请阅读我对Peter的评论 :) - goseib

0

是的,你可以用Java实现这个功能。 但是,对于地址操作,C++显然是更好的选择。 由于安全原因,Java不提供轻松操作地址的功能。

如果你在任何对象上调用hashCode(),它将返回该对象地址的字符串表示形式。


谢谢Mukherjee。我也可以使用toString并读取跟在“@”符号后面的子字符串。 - goseib

0
在Java中,您可以使用对象引用。没有void或整数指针,但由于每个对象都继承自Object,因此您可以使用强制转换Object引用。
import java.lang.*;

class test {

    static Object[] StoreObjectRefs = new Object[2];

    public static void main(String args[])
    {
        Integer x = new Integer(1);
        Float y = new Float(2.0);

        StoreObjectRefs[0] = (Object) x;
        StoreObjectRefs[1] = (Object) y;

        System.out.println((Integer)StoreObjectRefs[0]+(Float)StoreObjectRefs[1]);
    }

}

注意,函数中传递的是引用按值传递。


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