Java-修改对象';的内部数据,或使用修改后的数据创建新对象 问题
在Java中,根据标准代码样式和设计原则,何时更适合修改对象的内部数据,何时更适合使用修改后的数据创建新对象 例如,假设我有一个类Vector2D,它包含一个x分量和一个y分量,我想旋转这个向量: 接近A 然后可以使用Java-修改对象';的内部数据,或使用修改后的数据创建新对象 问题,java,oop,immutability,Java,Oop,Immutability,在Java中,根据标准代码样式和设计原则,何时更适合修改对象的内部数据,何时更适合使用修改后的数据创建新对象 例如,假设我有一个类Vector2D,它包含一个x分量和一个y分量,我想旋转这个向量: 接近A 然后可以使用vector1旋转Vector2D对象。旋转(角度) 方法B 然后可以使用vector1=vector1旋转Vector2D对象。旋转(角度) 迄今为止的调查结果 到目前为止,我对这个问题的研究使我相信方法B对于允许方法链接非常有用,例如vector1=vector1.rotate
vector1旋转Vector2D对象。旋转(角度)
方法B
然后可以使用vector1=vector1旋转Vector2D对象。旋转(角度)
迄今为止的调查结果
到目前为止,我对这个问题的研究使我相信方法B对于允许方法链接非常有用,例如vector1=vector1.rotate(angle)、scale(scale)
,它有自己的优点,更多的是在可读性方面
这也让我意识到方法B允许你使一个对象不可变,所以我想我的问题也是:
什么时候使对象不可变是合适的,特别是在本例中?(一般来说,对于点、向量、多边形等,所有这些类型是否都是不可变的?)
编辑:
我在写这篇文章时想到的项目是一个游戏,其中实体由多边形表示,并使用向量进行操作
我相信,由于预期的应用程序,确保类是线程安全的不应该是一个问题,因为向量和多边形数据无论如何只能由逻辑线程更改
这也意味着,这些操作可能每秒为每个实体执行60次(每个游戏滴答声)。这是否意味着每次实例化新对象所产生的任何开销都可能迅速增加?这取决于您将要实现的应用程序类型 如果是多线程的情况,您有许多线程并行执行任务,那么第二个选项会很方便,因为不可变对象本质上是线程安全的,您将避免许多潜在的麻烦。但这种方法也带来了一种折衷,即每次修改对象的内部状态都会产生创建新对象的开销
另一方面,如果您确信可以避免并行访问的危险,那么您可以使用第一种方法,这当然比直接比较快,因为它避免了大量对象实例化。对我来说,这取决于。可变对象对于多线程应用程序来说是危险的,而且当您要通过方法传递对象并且不想更改它们时,您应该使其不可变 因此,一般来说,如果您没有上述任何特殊问题,您可以使用可变对象来避免为自己、jvm和gc做额外的工作:) 到目前为止,我对这个问题的研究使我相信这种方法 B对于允许方法链接非常有用,例如 通过一种方法,您可以拥有setter并返回这些方法的修改对象。因此,您还可以使用“链接”功能 因此,真正的问题是: 什么时候使对象不可变是合适的 因为您希望为一个对象保证多个方面,例如:
- 对它没有任何副作用,因为任何可能的修改方法都将创建并返回一个新实例
- 也不需要为类的任何实例制作防御副本,因为它实际上是由类本身保证的
- 不用担心竞争条件:无法修改实例
- 不变规则设置
LocalDate
和LocalTime
)是不变性相关用法的好例子
在实际示例中,假设Vector2D
是一个API类,可以传递给不同类型对象的不同方法。使用可变类,可以在将对象传递给某些方法时对实例产生任何副作用。因此,它可能会以不需要的方式更改类的某些客户端的对象状态。
为了避免这种情况,该类的客户端可以进行防御复制。但它需要锅炉板和客户重复的代码。
对于不可变类,此问题不会发生。客户端可以根据需要使用实例,而不必担心其他客户端的使用。在方法A中,您仍然可以返回正在修改的对象并使用fluent API。这并不是第二种方法所独有的 关于不变性,有两个主要原因:
我建议您阅读有效的Java-第三版,第17项,以了解更多有关该主题的信息。我相信这是一本很棒的书,适合所有对成为更好的开发人员感兴趣的人。一般来说,你应该更喜欢使对象不可变。选择可变对象的原因可能是:
pandas
——它提供了两种选择)李>
public class Vector2D{
private int x;
private int y;
public Vector2D(int x, int y){
this.x = x;
this.y = y;
}
public void rotate(double angle){
//code for finding rotated vector
x = rotated_x;
y = rotated_y;
}
}
public class Vector2D{
private final int x;
private final int y;
public Vector2D(int x, int y){
this.x = x;
this.y = y;
}
public Vector2D rotate(double angle){
//code for finding rotated vector
Vector2D rotated = new Vector2D(rotated_x, rotated_y);
return(rotated);
}
}