繁体   English   中英

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

[英]How to determine if a Java method modifies an object passed as parameter

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

void foo(Boo& boo);

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

void foo(const Boo& boo);

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

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

void foo(Boo boo) {...}

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

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

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

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

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

List<String> readOnly = Collections.unmodifiableList(list);

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

List<String> readOnly = new ArrayList<>(list);

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

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

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

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

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

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

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

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

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

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

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

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

我必须同意其他答案,没有直接的方法来确定该方法是否会修改您的对象,是的,以确保该方法无法修改您的Object您必须做的就是在您身边。

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

这里方法名称出现在场景中。 继续使用方法的命名约定,我们必须查看一些方法声明,这些声明明确地说服了您的Object根本不会被更改。

例如,你知道Arrays.copyOf不会改变你的实际数组, System.out.println(boo)不会改变你的boo

方法名称是真正的武器 ,可以为方法用户提供尽可能多的信息。 (是的!这总是不可能,但要遵循相当不错的做法。)

让我们考虑在你的情况下说printBoo只会打印, copyBoo只会复制, clearBoo会重置所有属性, checkAndCreateNewBoo会检查你的boo Object并在需要时创建新的。

因此,最终,如果我们能以适当的方式调用者使用他们可以用事实放心Object会调用该方法后保持不变。

正如大家所说,更喜欢使用不可变对象,也避免使用void方法

这样的方法的可用目的

void foo(Boo boo) {...}

是更改对象本身的状态或更改作为参数传递的对象

void completOrder(Order order) { ... }
//or
void parserTokenEnded(String str) { ... }

有一种方法,方法开发人员应将参数标记为final,如果它不打算修改参数。

     public void test(final Object param)

然而,很少有人遵循这一点,因此很难知道。 然而,优秀的程序员遵循这条规则,尤其是编写api。 如果要编写方法并公开它。 make param final表示不会修改传递的对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM