【问题标题】:How can an instance communicate with its instantiator?实例如何与其实例化器通信?
【发布时间】:2012-06-26 18:55:35
【问题描述】:

举一个非常简单的例子:

Class A {
    B b = new B();
}

Class B {
    //unicorns and what-not
    //Something happens and I want to let A know
    //Yet I don't want to return and exit
}   

有没有什么方法可以让 B 在没有 Sockets 的情况下与 A 通信? 通过通信,我的意思是 B 向 A 发送值而不需要 A 在 B 上调用方法。

编辑:感谢您的回复。以下是我的后续问题:

如果我有以下情况,并且方法 signal() 被 B 的 2 个实例同时调用,这将导致每个 B 调用动作发生冲突两次。我能做些什么来解决它?

//Modified from Jon Skeet
public class A {
    private B b[];

    public A() {
        //for loop
        b[i] = new B(this);
    }

    public void signal() {
        //for loop
        b[i].action();
    }
}

public class B {
    A creator;

    public B(A creator) {
        this.creator = creator;
    }

    public void action() {
        //stuff
    }

    public void main(String[] args) {

        while(true)
            if(something==true) {
                creator.signal();
            }

   }
}

【问题讨论】:

  • 为什么不把A的引用传给B的构造函数,然后对这个引用进行操作呢?
  • 您要求的是 Observer 模式的简单示例。尽管人们已经给出了很好的答案,但知道这一点可能具有教育价值。

标签: java object communication instance


【解决方案1】:

您必须将 this 传递给 B 的构造函数:

public class A {
    private B b;

    public A() {
        b = new B(this);
    }
}

public class B {
    A creator;

    public B(A creator) {
        this.creator = creator;
    }
}

诚然,让this "escape` 在构造函数中通常不是一个好主意,但它经常比替代方案更干净。

【讨论】:

  • 如果您这样做,请确保您了解并发含义。例如,B.creator 不能保证看到任何在构造函数中分配的 A 字段——甚至是最后的字段。你可以在Aprivate final String name = "Foo"; 中有一个字段,如果B 的方法之一曾经调用creator.getName(),它可能会看到null。根据 JLS,它可能不会,但 JVM 会在它的权利范围内。
  • @yshavit:好点子——虽然它保证在同一个线程中看到新字段,当然。幸运的是,理智仍然存在于单线程案例中。
  • 在 Java 引入线程内竞争条件的那一天,我将转向 Scala,因为它是一种更简单的语言。 ;-)
  • @JonSkeet 我发布了一个后续问题。你能再帮我一次吗?
  • @drum:如果您发布有效代码会有所帮助。例如,目前您在类(而不是方法)中间有一个if 语句。演示问题的简短但完整程序会有所帮助 - 在单独的问题中可能会更好。
【解决方案2】:

// 独角兽之类的

如果A 在构造函数中传递了B 自身的一个实例,你ain't need no stinkin unicorns

class B {
    A instantiator;
    public B(A inst) { instantiator = inst; }
}


class A {
    B b = new B(this);
}

编辑(回答后续问题)

如果您想确保signal 的多次调用不会同时修改A 的状态,则应使用synchronized 关键字保护其关键部分。如果整个方法代表一个临界区,你可以在方法的声明中添加synchronized,像这样:

public synchronized void signal() {
    //for loop
    b[i].action();
}

【讨论】:

    【解决方案3】:

    让他们都可以访问同一个Queue。一个将元素放在上面,另一个从其中拉出元素。如果它们在不同的线程中,BlockingQueue 实现之一应该可以解决问题。

    【讨论】:

    • +1。消息传递是最简洁的方式,它也可以推广到其他解决方案(多个生产者或消费者等)
    【解决方案4】:
    Class A {
        B b = new B(this);
    
        public void MyCallback(Object o) {
    
            //Whatever
        }
    }
    
    Class B {
        //unicorns and what-not
    
        private A a;
    
        // .... assign a in constructor ...
    
        // wherever 
        a.MyCallback(MyUnicorn);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多