简体   繁体   English

在Java中,类可以引用包含它的另一个类的实例吗?

[英]In Java, can a class reference the instance of another class which contains it?

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

class B {
    private A a;
    public void setA(A a){
        this.a = a
    }
}

setA is called after an instance of A has been initiated. 在启动A的实例后调用setA I want to do this becase A has a method that B wants to call inside it. 我想这样做,因为A有一个B想要在其中调用的方法。

Sure, the language allows to do that. 当然,这种语言允许这样做。

But by doing this, you create what is called a circular dependency. 但是通过这样做,您可以创建所谓的循环依赖关系。 A needs B, and B needs A. That is considered bad practice in many cases. A需要B,而B需要A。在许多情况下,这被视为不良做法。

So, the real answer would be to step back and look at the problem you intend to solve. 因此,真正的答案是退后一步,看看您打算解决的问题。 And to then design a solution that does not create a circular dependency! 然后设计一个不会产生循环依赖的解决方案! Sometimes bidirectional connectivity is necessary, but in general, it can quickly become a source for potential problems later in. So do not buy into such a solution unless you have carefully evaluated your options and you didn't find a better way. 有时双向连接是必要的,但通常,它很快就会成为以后潜在问题的根源。因此,除非您仔细评估了自己的选择并且没有找到更好的方法,否则不要购买这种解决方案。

It might be helpful for example that method that B needs in an interface. 例如,接口B需要的方法可能会有所帮助。 Then your B object only needs an instance of that interface (which could be an A under the covers). 然后,您的B对象只需要该接口的一个实例(可以是一个A)。

Here A composes B. 这里A组成B。

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

And here B composes A : B组成A:

class B {
    private A a;
    public void setA(A a){
        this.a = a
    }
}

No design judgement, supposing that you are in a case where the bidirectional dependency is needed, you should avoid initializer or constructor to create instances of this class since you need an instance from A to create B and reversely. 无需设计判断,假设您需要双向依赖,则应避免使用初始化程序或构造函数来创建此类的实例,因为您需要A的实例来创建B,反之亦然。 Making this in an asymmetric way as in your sample code hides in a some way the relationship between these two classes. 如您的示例代码中那样,以非对称方式进行此操作以某种方式隐藏了这两个类之间的关系。
So you could use a setter or a factory approach to make it clearer. 因此,您可以使用设置器或工厂方法来使其更清晰。

Setter approach : 设置方法:

class A {
    private B b;
    public void setB(B b){
        this.b = b;
    }
}    

class B {
    private A a;
    public void setA(A a){
        this.a = a
    }
}

A a = new A();
B b = new B();
a.setB(b);
b.setA(a);

Or with a factory approach where you can rely on A or B class to expose the factory method according to the client need POV : 或者使用工厂方法,您可以根据客户的需求POV依赖于A或B类公开工厂方法:

class A{
    // ...
    public static A ofWithB(){
      A a = new A();
      B b = new B();
      a.setB(b);
      b.setA(a);
      return a;     
    }
}

A a = A.ofWithB();
B b = a.getB();

Any time code (in B in your example) has a reference to an instance of a different class ( A in your example), the rules governing its access to that instance's members (methods and fields) are the same: 任何时候代码(在您的示例中为B )引用不同类的实例(在您的示例中为A )时,用于控制对该实例成员(方法和字段)的访问的规则是相同的:

  • If the member is private , B cannot access it 如果成员是private成员,则B无法访问它
  • If the member is protected , B can access it only if B and A are in the same class, or B is a subclass of A 如果成员是protected ,则只有当BA属于同一类,或者BA的子类时, B才能访问它
  • If the member is package-private (no access modifier if it's in a class), B can only access it if B and A are in the same package 如果成员是包私有的(如果在类中,则没有访问修饰符),则B仅在BA位于同一包中时才能访问它
  • If the member is public , B can access it 如果成员是public ,则B可以访问它

(In an interface, no access modifier = public and you can't have other access modifiers.) (在界面中,没有访问修饰符= public并且您不能有其他访问修饰符。)

It doesn't matter whether the instance is held on a field of an instance of B . 实例是否保留在B实例的字段上并不重要。 The only thing that matters is what class the code trying to perform the access is in. 唯一重要的是试图执行访问的代码位于哪个类中。

See Controlling Access to Members of a Class 请参阅控制对类成员的访问

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM