java 如何检查对象不变性和可变性

bd1hkmkf  于 2023-05-12  发布在  Java
关注(0)|答案(4)|浏览(108)

项目的规范和要求中规定:
产品的ID不应更改..其类型为Long
这是否意味着,它必须是不可变的?如果是,如何以编程方式检查对象的不变性?

r9f1avp5

r9f1avp51#

这是否意味着它必须是不可变的?
是的,“不可变”和“不可变”是同义词。
如何检查对象的不变性

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

通过查看其文档和对象类的API。如果它不提供任何变化操作(setter等),那么对象是不可变的。这个类还需要是final或者没有protected字段,否则你可以继承它并修改受保护的字段。
例如,Long是不可变的(除非您使用反射来打破特定的实现)。如果仔细查看它的方法列表,就会发现它没有提供任何mutator操作,而且它是一个final类。
在这个答案发布后,您将问题修改为:
如何以编程方式检查对象的不变性
我觉得你做不到在反射中没有任何东西告诉您一个方法是否是一个mutator,并且基于方法名称做出假设是非常不可靠的。当然,如果对象的类是final,并且根本没有提供示例方法,这可能意味着它是不可变的。但是很多不可变类都有示例方法(包括Long)。

w8f9ii69

w8f9ii692#

是的,你可以确定一个对象是否是不可变的。然而,这是非常复杂的业务,因此解决方案不适合在Stack Overflow上的答案。
有两种方法可以确定类是否不可变:

  • 通过静态分析
  • 通过运行时检查

现有的静态分析工具是https://github.com/MutabilityDetector上的***MutabilityDetector***。
一个现有的运行时检查工具是***Bathyscaphe***at https://github.com/mikenakis/Bathyscaphe(我是作者)。
在我看来,静态分析在某些时候和某些场景下可能是有用的,但它并不能在任何时候都为问题提供完整的解决方案。一个完整的解决方案需要运行时检查,正如我在我的博客上解释的那样:https://blog.michael.gr/2022/05/bathyscaphe.html,这就是我写Bathyscaphe的原因。

ttcibm8c

ttcibm8c3#

如何以编程方式检查对象不变性?
我们不能。此外,我不觉得这 * 必须 * 以编程方式完成。进一步阅读,
让我们想象一个Exception类,如下所示:

public class MutationOfImmutableException extends Exception {

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

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

}

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

public void setName(String name) throws MutationOfImmutableException {
    throw new MutationOfImmutableException("Cannot mutate this immutable instance");
}

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

p.setName("Anees"); // Cannot do this until handled!

简而言之,如果你可以访问不可变的类Product,你可以从setId()抛出一个Checked Exception,以避免一切混乱!
更好的方法是将setters设置为私有,这样您就不会遇到这种情况。

2j4z5cfb

2j4z5cfb4#

问题不在于'Long'是否不可变;问题是“产品”的ID是否是不可变的。
通过将id字段设为私有、不实现任何将更改id的方法以及不在Product类中编写任何更改id的代码,可以提供id的不变性。
为什么Long的不变性与此无关?考虑这个例子,它无法满足id不可更改的要求:

class Product {
    private Long id;
    Product() { id = 42; }
    Long getId() { return id; }
    void setId(Long newId) { id = newId; }
       :
}

所有这些Long本身都是不可变的,但产品id仍然会发生变化:因为setId为id成员分配了一个 * different * immutable Long值。
但是,如果您只是删除setId方法(并且不在Product类中编写任何类似的内容),那么产品ID现在是不可更改的。

相关问题