7

我有一个Junit4静态导入方法的测试用例org.junit.Assert.assertEquals

import static org.junit.Assert.assertEquals;

在这个类中,我创建了一个实用方法来断言一些不实现 equals 的复杂内部类(并且也很难实现它)。

private void assertEquals(MyObj o1, MyObj o2)
{
    assertEquals(o1.getSomething(), o2.getSomething());
    assertEquals(o1.getSomethingElse(), o2.getSomethingElse());
    ...
}

我希望代码表现得好像我正在“重载”assertEquals我正在导入的方法,但看起来我的私有非静态方法正在隐藏静态导入的方法。我也尝试将我的方法变成publicand static(所有排列)但没有成功 - 我不得不重命名它。

它有这种行为的任何理由?我在文档中找不到对此行为的任何引用。

4

4 回答 4

3

您观察到的是调用Shadowing。当 java 中的两种类型具有相同的简单名称时,其中一种会影响另一种。阴影类型不能被它的简单名称使用。

最常见的阴影类型是隐藏字段的参数。通常会导致设置器代码看起来像setMyInt(int myInt) {this.myInt = myInt; }

现在让我们阅读相关文档

按需静态导入声明永远不会导致任何其他声明被隐藏。

这表明按需静态导入始终排在最后,因此与按需导入声明具有相同简单名称的任何类型将始终隐藏(隐藏)静态导入。

于 2011-07-06T12:52:22.810 回答
1

重载和覆盖在继承树中工作。但是静态导入不会建立继承。

如果你想在你自己的assertEquals 方法中使用junit 的assertEquals,你必须用className 来限定它,例如Assert.assertEquals。

使用 org.junit.Assert 的非静态导入。

于 2011-07-06T12:15:31.660 回答
0

这是有道理的。假设 javac 做你想做的事,它assertEquals(MyObj, MyObj)今天会选择你的方法。如果明天org.junit.Assert添加自己的assertEquals(MyObj, MyObj)方法怎么办?调用的含义在assertEquals(mo1,mo2)你不知情的情况下发生了巨大的变化。

有问题的是名字的含义assertEquals。Javac 需要确定这是org.junit.Assert. 只有在此之后,它才能进行方法重载解析:检查所有org.junit.Assert带有 name的方法assertEquals,选择最合适的一个。

可以想象,java 可以处理来自多个类的方法重载,但是正如第一段所示,它给开发人员带来了很大的不确定性,即他正在调用哪个类。因为这些类是不相关的,所以方法语义可能会有很大差异。

如果在编译时,开发人员毫无疑问该方法属于哪个类,则该类明天仍然可能重载该方法,从而更改调用的目标方法。但是,因为这是由同一个班级完成的,我们可以追究它的责任。例如,如果org.junit.Assert决定添加一个新assertEquals(MyObj, MyObj)方法,它必须知道一些以前的调用assertEquals(Object,Object)现在被重新路由到新方法,并且它必须确保没有会破坏调用站点的语义更改。

于 2011-07-06T21:04:45.770 回答
0

您偶然发现了方法隐藏,其中本地方法的存在“隐藏”了另一个类(通常是超类)。

我一直觉得静态导入方法虽然在语法上是可能的,但在某种程度上是“错误的”。

作为一种风格,我更喜欢导入类并TheirClass.method()在我的代码中使用。这样做可以清楚地表明该方法不是本地方法,并且好的代码的标志之一是清晰。

我推荐你import org.junit.Assert并使用Assert.assertEquals(...).

于 2011-07-06T12:48:59.313 回答