Java中对象能否在构造器内引用自身及初始化报错如何解决
Java构造器内部实现对象自引用关联的解决方案
你遇到的编译错误是Java局部变量初始化顺序的强制规则导致的:执行new A(new B(newObjectA))时,需要先计算构造参数的值,也就是先执行new B(newObjectA),但此时newObjectA还没有被A的构造方法完成赋值,属于未初始化的局部变量,因此编译器直接抛出错误。
除了你已经在使用的setter方案外,还有两种常用的实现方式:
构造器内直接传入this引用完成关联
直接在A的构造方法内部创建B实例,将当前正在构造的A实例(this)作为参数传入B的构造方法:public class Main { public static void main (String[] args) throws java.lang.Exception { A newObjectA = new A(); } class A{ B b; A(){ // 构造A的过程中直接创建关联的B实例 this.b = new B(this); // 其余A的构造逻辑 } } class B{ A referenceToA; B(A a){ this.referenceToA = a; // 其余B的构造逻辑 } } }注意:该方式会将还未完成全部构造逻辑的A实例暴露给B,如果B的构造方法中会调用A的成员方法、访问未初始化的成员变量,可能会出现预期外的行为,需要提前做好逻辑校验
工厂方法封装关联逻辑,避免半初始化对象逸出
把A的构造方法私有化,对外提供工厂方法,保证A完全构造完成后再和B建立关联,是更安全的实现:public class Main { public static void main (String[] args) throws java.lang.Exception { A newObjectA = A.createInstanceWithB(); } class A{ B b; // 构造方法私有化,禁止外部直接创建 private A(){ // 完成A的全部基础构造逻辑 } public static A createInstanceWithB() { A a = new A(); // A完全构造完成后再初始化B并建立关联 a.b = new B(a); return a; } } class B{ A referenceToA; B(A a){ this.referenceToA = a; } } }
如果你需要外部自定义B的实例,你目前在用的setter方案是行业内非常通用的实现,你也可以在A的构造方法中调用B的setter完成反向关联,进一步简化调用侧的代码:
class A{ B b; A(B b){ this.b = b; // 直接在A的构造器中完成反向关联 b.setReferenceToA(this); } } class B{ A referenceToA; // 构造方法只完成B自身的初始化 B(){ // B的构造逻辑 } public void setReferenceToA(A a) { // 可选:加校验避免重复关联 if (this.referenceToA != null) { throw new IllegalStateException("关联关系已存在,不可重复修改"); } this.referenceToA = a; } } // 调用侧代码 A newObjectA = new A(new B());
内容的提问来源于stack exchange,提问作者João Schmidt
相关产品推荐
相关产品推荐

