10

我已经阅读了有关使用 RMI 传递变量的各种文章。

他们中的一些人说在 RMI 中不可能通过引用传递变量。例如:这个这个

而其他人则说这是可能的。例如: 这个这个这个

任何人都可以解决这个问题吗?:)

4

3 回答 3

6

重要提示:如果通过引用传递意味着修改方法内部的参数值并更改调用者中的原始变量,则不能。如果您想要做的是传递对对象的引用的副本,以允许该方法与您的某个对象交互......是的,您可以。答案探讨了第二种选择。

是的。但它必须是一个 RMI 对象。在这种情况下,RMI 存根将通过副本传递。

RMI 以两种方式传递参数和返回值:

  1. 复制整个对象
  2. 发送一个远程引用(如果它是一个引用,它必须是远程的!)。

样本

猜猜我们有一个服务。它是一个 RMI 对象,通过 RMI 注册表发布,因此客户端可以访问它。客户端可以调用它的方法(创建一些东西)并且服务想要返回对那个新创建的对象的引用。不是序列化副本,而是对服务器内存空间中创建的对象的引用。

import java.rmi.Remote;
import java.rmi.RemoteException;

// normally published object
public interface MyService extends Remote
{
    // creates something and return a "handle" to it
    public MyHandle createX(SomeSerializableObj param1) throws RemoteException;
}

// interface for object that the service will return a reference to...
public interface MyHandle extends Remote
{
    void doOne();
    void doTwo();
}

在此示例中,您可以:

创建 MyService 的实现并发布它

Registry registry = LocateRegistry.createRegistry(port);
MyService stub = (MyService) UnicastRemoteObject.exportObject(server, 0);
registry.bind("myService", stub);`

然后,一些 RMI 客户端可以获得对它的引用

Registry registry = LocateRegistry.getRegistry(server, port);
MyService serv1 = (MyService) registry.lookup("myService");

并且通过对服务对象的引用可以获得对其他 RMI 对象的引用。

MyHandle handle1 = serv1.createX(...);
handle1.doOne()

在这个例子中,方法参数是序列化的(它应该是一个 Serializable 类),而返回的对象是对在服务器中创建的对象的 RMI 引用。

createX(...) 的实现可能是:

public MyHandle createX(...) {
   MyHandle handle = new MyHandleImpl(); // create an implementation
   createdHandlers.add(handle); // add it to some structure (just a sample)
   return handle; // return the implementation. RMI will send to client a RMI reference to this very instance
}
于 2012-06-25T10:28:54.023 回答
3

您的参考资料:

(1) 表示 RMI 不支持通过引用传递。我同意。

(2) 表示 RMI 不支持 in-out 参数。我同意。

(3) 只是展示了按引用传递和按值传递引用之间的常见混淆。RMI 是后者,就像 Java 的其余部分一样。

(4) 错误。

(5) 完全不连贯。RMI 中没有传递引用。

RMI 的远程“按值引用”在语义上与 Java 的本地“按值引用”本质上没有什么不同,除了其他可能的故障模式。

您阅读的意思是,对于非远程引用,RMI 对象参数和结果是通过对象序列化按传递的,而不是通过 Java 的按值引用的参数传递方法。

于 2012-06-25T23:12:22.650 回答
0

真正意义上的不,你不能。

当您通过“引用”传递某些内容时,您真正在做的是将指针传递给内存中的某个位置。当调用者和被调用者是同一个进程时,这非常有效,它们可以访问完全相同的堆。但是将内存引用从计算机 A 传递给计算机 B 是没有意义的,A 无法访问 B 的内存*。

然而,RMI 允许您获得对远程对象的“引用”,但这并不完全相同,并且必须提前请求,将您的对象之一传递给服务器将导致副本。

直接从马嘴里(http://www.oracle.com/technetwork/java/javase/tech/index-jsp-138781.html#3)

RMI 使用标准的 Java 对象序列化机制来传递对象。引用远程对象的参数作为远程引用传递。如果方法的参数是原始类型或本地(非远程)对象,则将深层副本传递给服务器。返回值的处理方式相同,但方向相反。RMI 允许您传递和返回本地对象和对远程对象的引用的完整对象图。

您可以通过引用传递远程对象,但不能将本地对象作为引用传递回服务器。

*从技术上讲,您可以在一些大型分布式共享内存系统中,但我怀疑这就是 OP 所说的。

于 2012-06-26T01:18:11.207 回答