JavaBean的缺点-在构建过程中不一致

JavaBean的缺点-在构建过程中不一致,java,effective-java,Java,Effective Java,, JavaBean在构造过程中可能处于不一致状态 我不能理解这一点,如果一个对象是在一个方法中构造的,那个么它将如何变得不一致,若必须发生异常,那个么这个异常也可能发生在构造函数中。这与线程有什么关系?想象一个线程模型,其中ThreadUtils.doFoo(FooBean fb)将产生一个线程,该线程将与fb一起工作fb可以像传递给该线程以定义其计算的参数一样简单。现在,采用以下构造函数: public FooBean(int i, int j, int k, int l, int port

,

JavaBean在构造过程中可能处于不一致状态


我不能理解这一点,如果一个对象是在一个方法中构造的,那个么它将如何变得不一致,若必须发生异常,那个么这个异常也可能发生在构造函数中。这与线程有什么关系?

想象一个线程模型,其中
ThreadUtils.doFoo(FooBean fb)
将产生一个线程,该线程将与
fb
一起工作
fb
可以像传递给该线程以定义其计算的参数一样简单。现在,采用以下构造函数:

public FooBean(int i, int j, int k, int l, int port){
    ThreadUtils.doFoo(this);
    someListField = Arrays.asList(i, j, k, l);
    this.port = port;
}
这会导致
从构造函数中泄漏。如果由于某种虚假的原因,派生线程在列表被正确实例化和分配之前就执行了操作,那么就会有一个线程在
this
的不一致状态下工作。例如,如果新线程使用
端口
侦听套接字,并且
泄漏,则套接字可能侦听端口0(数字字段的默认值),而不是端口
端口

事实上,如果
this
泄漏并从其他地方获得可访问的强引用,则构造函数中的异常可能是一个问题

但是,以下构造函数是安全的:

public FooBean(int i, int j, int k, int l, int port){
    someListField = Arrays.asList(i, j, k, l);
    this.port = port;
    ThreadUtils.doFoo(this);
}

这是因为在Java内存模型中,字段是在线程生成之前存储的。

本书中介绍了以下bean:

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
其中,由
SetServiceSize(int)
SetServiceings(int)
设置的
servingSize
SetServicesSize(int)
是营养事实的基础,至少在书中是如此

但如果你只是打电话:

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setCalories(100);
然后将不会设置
服务
字段。因此,结果实例现在处于无效状态

因此,如果调用需要有效实例的方法,例如
healthRiskCalculator.calculateHealthRisk(NutritionFacts facts)
,则对象内或
healthRiskCalculator
中会出现异常

因此,现在您可以在调用
calculateHealthRisk()
时检查对健康的损害,但可能有许多方法可以读取或使用对象实例。此外,您可能还为其他产品创建了许多无效实例。换句话说,这不是快速失败


因此,没有使用bean创建构造对象的故障安全方法。这不是线程的特殊情况,您可以在单个线程中创建一个无效的bean实例。

@owlstead可能是因为问题问“这与线程有什么关系?”@MattCoubrough这一章本身就没有线程。此外,bean示例主要关注setter,这在示例中不存在。我只是在阅读书中的特定句子时放下了kindle,用Google搜索了一下,很快就找到了。我相信,虽然关注的范围不仅仅是线程,但在构造多线程使用的对象时,更常见的是观察这种行为,除非您确保没有人戳构造,尤其是在setter之间。我们再次讨论了这个问题,这让我思考。如果我提供一个带有强制参数的构造函数会怎么样?我猜代码将从JavaBeans模式中转移,但它仍然可以工作,对吗?当然,当我创建实例时,我总是这样做。如果构造函数变得太复杂,那么你可以使用工厂方法,甚至对象工厂。同意Batty的观点,一个带有强制参数的构造函数,后跟对可选参数的setter调用,应该也能正常工作。@PrateekJassal我当然不反对这种强制参数的构造函数。但再一次,这个答案主要解释了为什么bean可以处于不一致的状态。bean具有空构造函数,以便以后可以设置属性。