Java 如何检查对象的不变性和易变性

Java 如何检查对象的不变性和易变性,java,immutability,Java,Immutability,本项目的规范和要求中规定: 产品Id不应更改。它的类型为Long 这是否意味着,它必须是不变的?如果是,如何以编程方式检查对象的不变性 这是否意味着,它必须是不变的 是的,“不可改变”和“不可改变”是同义词 如何检查对象的不变性 (更新问题的更新答案见下文) 通过查看对象类的文档和API。如果它不提供任何变异操作(setter等),那么该对象是不可变的。该类还需要是final或没有受保护的字段,否则您可以对其进行子类化并修改受保护的字段 例如,是不可变的(除非您使用反射来分解特定的实现)。如果您

本项目的规范和要求中规定:

产品Id不应更改。它的类型为
Long

这是否意味着,它必须是不变的?如果是,如何以编程方式检查对象的不变性

这是否意味着,它必须是不变的

是的,“不可改变”和“不可改变”是同义词

如何检查对象的不变性

(更新问题的更新答案见下文)

通过查看对象类的文档和API。如果它不提供任何变异操作(setter等),那么该对象是不可变的。该类还需要是
final
或没有
受保护的
字段,否则您可以对其进行子类化并修改受保护的字段

例如,是不可变的(除非您使用反射来分解特定的实现)。如果您查看它的方法列表,它不提供任何mutator操作,它是一个
final


发布此答案后,您将问题修改为:

如何以编程方式检查对象的不变性


我想你做不到。在反射中没有任何东西可以告诉你一个方法是否是一个变异子,而且基于方法名进行假设是非常不可靠的。当然,如果对象的类是
final
,并且提供了no实例方法,这可能意味着它是不可变的。但是很多不可变类都有实例方法(包括
Long
)。

问题不在于“Long”是否不可变;问题在于“产品”的id是否是不可变的

通过使id字段私有、不实现任何将更改id的方法以及不在产品类中编写任何更改id的代码,可以提供id的不变性

为什么长期的不变性不相关?考虑这个例子不能满足您的ID不可变的要求:

class Product {
    private Long id;
    Product() { id = 42; }
    Long getId() { return id; }
    void setId(Long newId) { id = newId; }
       :
}
所有这些Long本身都是不可变的,但是产品id仍然会发生变化:因为
setId
为id成员分配了不同的不可变Long值

但是,如果您只是删除了
setId
方法(并且不在产品类中编写任何类似的内容),那么产品id现在是不可更改的

如何以编程方式检查对象的不变性

我们不能。此外,我不认为这必须通过编程来完成。进一步阅读

让我们有一个虚构的
异常
类,如下所示

public class MutationOfImmutableException extends Exception {

  /**
   * 
   */
  private static final long serialVersionUID = 1L;

  public MutationOfImmutableException(String string) {
    super(string);
  } 

}
我们班(我想不出一个好名字,但我想这传达了这个想法)有

并且,在我们的主类中,每当有人错误地调用
setName()
,编译器都会警告我们正确处理异常

p.setName("Anees"); // Cannot do this until handled!
简言之,如果您有权访问不可变的类
产品
,则可以从
setId()
抛出已检查异常,以避免一切失控


更好的是,将您的
设置程序设置为私有,这样您甚至不会遇到这种情况。

这是否意味着它必须是不可变的对如何检查对象的不变性你的意思是编程还是设计?@Arthuratotout编程..我修改了问题#我们可以通过编程检查吗..有什么地方可以做吗so@user2121-我不这么认为。我不明白你为什么要这么做。@user2121:如果你要找的是简单的标志或类似的东西,那就没有了。但是,可以通过编程方式检查大多数手动检查的内容,但这通常不值得(因为大多数情况下,您希望验证整个类型是不可变的,而不仅仅是某个特定实例,有时无法通过编程方式完成)(例如,
列表
字段可能是不变的,也可能不是不变的,这取决于它引用的内容)。如果不能使用setter,为什么还要使用setter呢?
p.setName("Anees"); // Cannot do this until handled!