使用引用获取java对象

3ks5zfa0  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(474)

这个问题在这里已经有答案了

在java中通过引用获取对象(2个答案)
26天前关门了。
我脑子里有这个问题,我非常需要找到答案。
我的问题是:如何获取对象的引用(比如内存地址),然后使用引用获取对象(注意:我知道对象(在数组中)的位置)。我听说有一些方法可以使用不安全类,甚至jna来做我想做的事情(我对这两个都不了解,但很乐意学习!)
我在做什么:
我制作了一个应用程序(app1),通过插装插入到另一个应用程序**(app2)**中,这个应用程序(app1)通过反射api将从(app2)获取的数据通过rmi发送到我的另一个应用程序(app3)。数组中的对象在值方面不断变化,所以我所做的是获取对象并读取它们的数据,但是当我尝试使用以前获得的对象(通常由 getDeclaredField(fieldName).get(PreviouslyObtainedObject); 但是我无法在当前应用程序(app1)上保留以前获取的对象,因为它是不可变量的,所以我需要获取此对象的引用,以便以后可以获取它。
我试过的:
我试着用hashcode来做,但是hashcode只是在对象的值改变时不断地改变/消失,而hashcode可能与其他对象相同,所以这会产生另一个问题。
我试过用xstream,gson等做。。但是使用xml/json它创建了一个新的对象,并且与以前获得的对象无关。因此,当我尝试使用json/xml创建的对象获取对象的更新信息时,它会返回旧信息,因为它不等于先前获取的对象。就像这样 getDeclaredField(fieldName).get(PreviouslyObtainedObject) 返回有关对象的更新信息,但 getDeclaredField(fieldName).get(JSON/XMLVersionOfPreviouslyObtainedObject) 不返回新数据。
我不能做对象->字节数组,因为对象是不可变量的。
问题中没有代码,因为我觉得代码对问题没有作用。为了获得更多关于我正在做什么的信息,您可以查看我之前的一个问题:在java中通过引用获取对象注意:这个问题和我之前的问题有区别,因为之前的问题讨论了将对象 Package 或转换为json或xml格式的方法,而这个问题只是为了获取引用。
我要做的事情的摘要(为了更清楚):
我有两个应用程序:第一个应用程序(app1):插入到另一个应用程序中的应用程序(收集数据并发送)
第二个应用程序(app2):从插入指令的数据接收数据并执行逻辑的应用程序。。
app1通过反射api从其插入的应用程序获取数据,如下所示(getdeclaredfield(fieldname).get(object/null);)app1将对象引用(内存地址/hashcode/这是我想要的)和对象的当前值发送给app2。app2在需要时发回引用,并获取对象更新的数据。
就像在代码中:
当我第一次想要得到一个对象时,我使用反射来访问一个对象数组,然后通过它来找到我的完美对象,就像这样:

Object[] obArray = (Object[]) getClassLoader().loadClass("className").getDeclaredField("fieldName").get(null);
for(Object ob : obArray) {
    if(ob is what I want) return ob;
}

然后,如果我想得到ob(我在上面获取的对象)的更新信息。我愿意 getClassLoader().loadClass(className).getDeclaredField(fieldName).get(ob); 现在由于我处理的对象太多,我无法将获取的对象存储在同一个应用程序中,因此我必须获取对它们的引用(比如内存地址或哈希代码)才能发送到app2,以便app2可以在以后将其发送回app1,以取回对象并获取有关它的更新信息。

brgchamk

brgchamk1#

当您使用rmi时,您已经在使用一个框架来维护跨jvm的引用。但它不支持在将引用传递给另一个jvm并返回之后检索原始的本地对象引用,因为它只允许通过远程接口与被引用的对象通信。
但由于您的实际目标是允许读取引用对象的字段,因此可以通过远程接口导出此操作。
这是这样一个通道的草图。请注意,它包含一些在生成代码时不会执行的操作(如设置) sun.rmi.dgc.server.gcInterval 为了演示的目的。

public class RmiApp implements RmiAppB {
    public static void main(String[] args) throws Exception {
        System.setProperty("sun.rmi.dgc.server.gcInterval", "1000");
        if(args.length == 0) runAppB(); else runAppA();
    }

    private static void runAppA() throws Exception {
        String me = String.format("App A (pid%6d) ", ProcessHandle.current().pid());
        System.out.println(me + "started");
        Registry r = LocateRegistry.getRegistry(12348);
        RmiAppB appB = (RmiAppB)r.lookup("foo");
        InnocuousObject obj = new InnocuousObject("a local string", 42, 1.234f);
        System.out.println(me + "sending reference");
        appB.passTheReference((WrappingReference)
            UnicastRemoteObject.exportObject(new WrappingReferenceImpl(obj), 0));

        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
        System.out.println(me + "changing fields");
        obj.field1 = "another string";
        obj.field2 = 0;
        obj.field3 = 0.1f;
        obj = null; // we don't need to keep a strong reference

        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));

        System.exit(0);
    }

    private static void runAppB() throws Exception {
        System.out.printf("App B (pid%6d) started%n", ProcessHandle.current().pid());
        Registry r = LocateRegistry.createRegistry(12348);
        r.bind("foo", UnicastRemoteObject.exportObject(new RmiApp(), 0));
        //UnicastRemoteObject.exportObject(new RmiApp(), 12345);
        new ProcessBuilder(
            Paths.get(System.getProperty("java.home"), "bin", "java").toString(),
            "-cp", System.getProperty("java.class.path"),
            RmiApp.class.getName(), "runA")
            .inheritIO().start().waitFor();
        System.exit(0);
    }

    @Override
    public void passTheReference(WrappingReference o) throws RemoteException {
        String me = String.format("App B (pid%6d) ", ProcessHandle.current().pid());
        System.out.println(me + "received object");
        System.out.println(me + "querying field1 " + o.getField("field1"));
        System.out.println(me + "querying field2 " + o.getField("field2"));
        System.out.println(me + "querying field3 " + o.getField("field3"));
        CompletableFuture.runAsync(() -> {
            LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(3));
            try {
                System.out.println(me + "querying field1 " + o.getField("field1"));
                System.out.println(me + "querying field2 " + o.getField("field2"));
                System.out.println(me + "querying field3 " + o.getField("field3"));
            } catch(RemoteException ex) {
                ex.printStackTrace();
            }
        });
    }
}

interface RmiAppB extends Remote {
    void passTheReference(WrappingReference o) throws RemoteException;
}

interface WrappingReference extends Remote {
    Object getField(String nra) throws RemoteException;
}

class WrappingReferenceImpl implements WrappingReference {
    InnocuousObject referent;

    WrappingReferenceImpl(InnocuousObject referent) {
        this.referent = referent;
    }

    @Override
    public Object getField(String nra) throws RemoteException {
        try {
            return referent.getClass().getDeclaredField(nra).get(referent);
        } catch(NoSuchFieldException|IllegalAccessException ex) {
            throw new RemoteException(null, ex);
        }
    }
}

class InnocuousObject {
    String field1;
    int field2;
    float field3;

    public InnocuousObject(String field1, int field2, float field3) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("InnocuousObject.finalize()");
    }

    @Override
    public String toString() {
        return field1;
    }
}

在一次运行中,它打印了

App B (pid  8924) started
App A (pid  9132) started
App A (pid  9132) sending reference
App B (pid  8924) received object
App B (pid  8924) querying field1 a local string
App B (pid  8924) querying field2 42
App B (pid  8924) querying field3 1.234
App A (pid  9132) changing fields
App B (pid  8924) querying field1 another string
App B (pid  8924) querying field2 0
App B (pid  8924) querying field3 0.1
InnocuousObject.finalize()

显示远程引用如何在另一个jvm持有远程引用时保持对象的活动状态,但在不存在远程引用时允许其垃圾回收。
进一步注意目标 InnocuousObject 不知道通过封装进行远程访问 WrappingReferenceImpl 执行反射访问的。这似乎支持由app1检测app2的场景,而只有app1知道远程访问。

相关问题