4

假设构造函数在代码的客户端部分(被翻译为 javascript 的部分)中运行。回调方法 onSuccess 确实修改了类的实例变量。回调被实现为匿名类,因此可以使用 OuterClass.this 访问外部类的实例。

通常在纯 Java 中我们不应该做这样的事情,因为这样做,'this' 引用可以在对象构造完成之前逃逸。

但它是否也适用于将 Java 代码转换为 Javascript 的情况?我假设 javascript 代码是由网络浏览器中的单个线程执行的,所以这应该不是问题(单线程 => 没有可见性问题)?

4

2 回答 2

3

一方面,你是对的——问题不能由单独的线程触发,因为 JavaScript 是单线程的。

回调事件肯定会由在当前事件处理程序(构造当前对象的事件处理程序)完成后启动的事件处理程序处理。所以他们只会看到完全构造的对象。

另一方面,您通常不需要线程来利用基本问题。这是一个简单的例子:

final A a = new A();
final B b = new B(a);
public class A {

  private B b;

  public void setB(final B b) {
    this.b = b;
  }

  public void letBSaySomething() {
    b.saySomething();
  }
}
public class B {

  private A a;
  private final int some;

  public B(final A a) {
    this.a = a;
    a.setB(this);

    a.letBSaySomething();
    some = 55;
    a.letBSaySomething();
  }

  public void saySomething() {
    RootPanel.get().add(new Label("Hello " + some));
  }
}

这导致输出

Hello 0
Hello 55

(虽然“一些”是最终的)。这在 GWT(已编译/未编译)和纯 Java 程序中都会发生。

于 2013-04-08T10:26:15.370 回答
2

AsyncCallback 本身只是一个类。在生产模式下发送 RPC 请求时,保证结果会通过 XmlHttpRequest 异步传入;在已编译的 javascript 中,在构造完成之前泄漏引用是 100% 不可能的,因为回调将在单独的 javascript 执行堆栈中被调用。

然而,在 gwt-dev 模式下,应该是异步的事情并不总是如此。就个人而言,我放弃了 gwt-dev 而不是 super-dev-mode,并且仅在我确实需要 java 调试器时才使用 gwt-dev,所以我无法确定它是否会不受构造问题的影响(测试它并找出!)。

如果您没有在构造函数中发送任何请求,您将是 100% 安全的。如果您随后以不安全的方式访问 OuterClass.this,则仅创建异步回调只会导致问题,而不管涉及的类如何。

于 2013-04-09T01:28:52.163 回答