【问题标题】:Java: Possible to have mutual, final class references?Java:可能有相互的最终类引用?
【发布时间】:2009-08-21 03:56:33
【问题描述】:

假设我有两个名为 A 和 B 的类,它们相互关联,因此如果每个类的对象都包含对另一个的引用,则最方便。换句话说,A类有一个B类的变量“b”。B类有一个A类的变量“a”。这样,每个类中的代码都可以轻松访问另一个类。

有没有办法将此关联设置为“最终”?即A类中的变量b是最终的,B类中的变量a是最终的?似乎在构造函数中设置这些引用(正如 final 关键字所要求的)需要一种不合逻辑的循环引用。

这更像是一个概念问题,而不是一个实际问题。谢谢!

【问题讨论】:

    标签: java class final


    【解决方案1】:

    是的,如果其中一个类负责创建另一个类的实例,这是可能的。 第一个构造函数可以将自身的一个实例作为第二个类的参数传递。

    public class A {
        final B b;
        public A() {
            b = new B(this);
        }
        public B getB() {
            return b;
        }
    }
    public class B {
        final A a;
        public B(A a) {
            this.a = a;
        }
    }
    

    【讨论】:

    • 虽然这种方法可能有效,但它可能很危险,因为 B 构造函数正在接收对尚未完全构造的元素的引用。例如,假设 A 有另一个在 'b' 之后初始化的字段,并且 B 构造函数尝试访问它。它将获得一个未初始化的对象。从 B 构造函数调用 A 的方法也是如此,或者如果 A 稍后被扩展......也许重新设计会是一个更好的选择。
    • 稍微更简洁的是让一个类成为另一个类的内部类。 (注意:当您将B 构造函数公开时,另一个包中的另一个类可以为A(或null!)的任何实例构造另一个B。)
    • 也许最好的方法是让两个构造函数都封装作用域,并提供某种工厂方法来提供 A。这样就不会有人意外滥用类。
    【解决方案2】:

    正如另一位发帖者指出的那样,可以通过让其中一个类负责构造另一个类并将自身传递给另一个对象的构造函数来实现这一点。

    但是,如果您希望第一个类的一个实例对应于第二个类的一个实例(您似乎这样做),这会导致潜在的问题。另一个对象可能会将对第一个类的现有引用传递给第二个类的构造函数,从而允许出现无效情况(第二个类的实例现在具有对第一个类的实例的引用,该实例引用了 第二类的不同实例)。

    当您考虑到第二个类的构造函数不能引用第一个类的未初始化成员时,会出现更多潜在问题。

    我的建议是,如果这两个类是如此相互关联,以至于您希望它们各自具有对另一个的最终引用,只需将它们设为同一个类。然后你总是得到另一个对象的最终引用:this

    【讨论】:

    • 结合这两个类没有帮助。循环引用可以并且经常发生在同一类的对象中。考虑树中的节点,其中每个节点都有对其父节点和子节点的最终引用,或者尝试创建一个不可变的双向链表,其中包含对下一个和前一个节点的最终引用。
    【解决方案3】:

    如果您使用像 guice 这样的 Di 容器,则无需在构造函数中传递明显的引用即可实现这一点 - 正如之前指出的那样,这可能容易出错。

    声明依赖 a-b 和 b-a 并将其中一个注入另一个类。 guice 会做一些神奇的事情,让这两个领域都是最终的。基本上它会先注入一个代理,然后再设置它的委托人。

    您需要一个代码示例吗?

    【讨论】:

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