Java 将可变对象转换为不可变对象

Java 将可变对象转换为不可变对象,java,immutability,Java,Immutability,我想使bean不可变,传统的方法是将所有字段设置为final,并在构造函数中设置它们的值 在我看来,这很有效,除非有许多字段需要通过一些复杂的逻辑相互依赖地计算,或者当多个服务需要参与设置值时 工厂是另一种方法,但我不能想出一个整洁的模型来避免太多的代码 我想做的是创建一个bean的可变实例,一旦它被完全填充,我想“烘焙”它,即使它不可变 是否有一种方法可以在运行时更改实例,将字段从non-final更改为final,而无需子类化等 我相当肯定,仅仅使用标准java/reflection是不可能

我想使bean不可变,传统的方法是将所有字段设置为final,并在构造函数中设置它们的值

在我看来,这很有效,除非有许多字段需要通过一些复杂的逻辑相互依赖地计算,或者当多个服务需要参与设置值时

工厂是另一种方法,但我不能想出一个整洁的模型来避免太多的代码

我想做的是创建一个bean的可变实例,一旦它被完全填充,我想“烘焙”它,即使它不可变

是否有一种方法可以在运行时更改实例,将字段从
non-final
更改为
final
,而无需子类化等

我相当肯定,仅仅使用标准java/reflection是不可能做到的,但我怀疑使用一些字节码更改(如javassist等)是可能的


一个好的整洁的工厂模式也可能会被选中……

Joshua Bloch在他的书《有效Java,第二版》中,在“创建和销毁Java对象”的第二章中,已经解决了这个问题:

使用此对象的示例如下:

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();
从上面的示例中可以看到,在将可变对象构建为不可变对象之前,可以先创建可变对象。对象的生成器也可以调整并重新使用,以生成多个不可变的对象。例如:

NutritionFacts.Builder food = new NutritionFacts.Builder(1, 1);
NutritionFacts salad = food.calories(100).build();
NutritionFacts bigMac = food.calories(1000).build();

听起来你在寻找“构建器”模式,为什么不在你的bean之外进行计算呢?参与设置值的多个服务看起来有点像您可以改进您的结构这里-这就是你想要的吗?@Marvin这些calc肯定是在bean之外完成的-在生成calc时需要涉及多个服务,我宁愿使用bean作为存储,也不愿创建一整套同名的变量
NutritionFacts.Builder food = new NutritionFacts.Builder(1, 1);
NutritionFacts salad = food.calories(100).build();
NutritionFacts bigMac = food.calories(1000).build();