如何确定Java方法是否修改作为参数传递的对象

Ita*_*key 32 java immutability

我来自C++背景,目前我正在学习Java.当我尝试使用某些第三方库时出现了一个问题.如何确定对作为参数的对象引用的方法的调用是否修改了对象?在C++中,由于使用了const关键字,因此很清楚.如果方法签名是:

void foo(Boo& boo);
Run Code Online (Sandbox Code Playgroud)

我知道引用的对象可能会被修改,而如果方法签名是:

void foo(const Boo& boo);
Run Code Online (Sandbox Code Playgroud)

编译器保证不会修改引用的对象.

我没有在Java中看到类似的东西,因为只有引用本身可以被声明为final,而不是引用的对象,并且最终的参数在第一个地方没有多大意义,因为它无论如何都是通过值传递的.因此,当我看到一个方法,如:

void foo(Boo boo) {...}
Run Code Online (Sandbox Code Playgroud)

如何确定boo引用的对象是否在函数体内修改(可能使用注释)?如果没有办法知道,是否有一些广泛使用的约定或一些最佳实践来避免混淆和错误?

Pet*_*rey 26

如何确定boo引用的对象是否在函数体内修改(可能使用注释)?

唯一的方法是不幸地读取代码.

如果没有办法知道,是否有一些广泛使用的约定或一些最佳实践来避免混淆和错误?

常见的惯例是在需要时使用包装器传递无法修改的对象.这样可以确保类无法修改对象.

List<String> readOnly = Collections.unmodifiableList(list);
Run Code Online (Sandbox Code Playgroud)

如果对象是Cloneable,您也可以使用,clone()但另一种常见方法是使用副本.

List<String> readOnly = new ArrayList<>(list);
Run Code Online (Sandbox Code Playgroud)

如果您关心此类行为,单元测试可以显示方法是否修改了对象.如果您已经进行了单元测试,通常需要一两行来检查.

  • `clone`仅在已经存在正确实现的极少数情况下才有用.在新代码中,没有理由公开`clone`,甚至不是普通的类; 只是提供一个复制构造函数. (2认同)

Mur*_*nik 14

不幸的是,这种语言没有内置这种设施.一个好的防御性做法是将您传递的数据对象定义为不可变的(即,没有任何允许修改其状态的公共方法).如果你真的关心这个问题,你可以在将对象传递给你不信任的方法之前复制/克隆一个对象,但这通常是一个多余的预防措施.


Kas*_*erg 8

注意:这个答案是更详细的版本

您还可以在代码中编写纯度或副作用注释 - mernst

在编译时可以通过注释检查的各种事物之间存在Checker FrameworkIJG Immutablity检查器.此检查器允许您使用@Immutable或注释对象引用@ReadOnly.

问题是您经常需要自己注释库.为了简化您的任务,Checker Framework可以自动推断部分注释; 你仍然需要自己做很多事情.

  • 关于[Checker Framework](http://checkerframework.org/)的状态,Google每天都会使用它来处理数百个项目.它也被华尔街以及许多其他从业者和学者使用.它不是官方标准,也没有任何相关的JSR - 它只是一个有用的工具. (2认同)

mer*_*nst 6

Java语言中没有内置副作用分析.

您可以通过手动检查执行副作用分析,但是存在一些自动化过程的工具.

您可以使用一个推理工具(1,2, 3),以检测是否你的代码的副作用的参数.

你也可以写纯度或副作用的注释你的代码,然后用一个检查/验证工具(1,2),以确保您的代码符合你写的注释.

所有上述链接工具都有局限性,但您可能会发现它们很有用.如果您了解其他工具,请在评论中提及.