Java 当类具有与导入的方法同名的方法时,“导入静态”不起作用

Java 当类具有与导入的方法同名的方法时,“导入静态”不起作用,java,static-import,Java,Static Import,我有一个Junit4测试用例,它静态地导入org.junit.Assert.assertEquals方法 在这个类中,我创建了一个实用程序方法,用于断言一些复杂的内部类,这些类不实现equals(并且很难实现它) 我希望代码的行为就像我正在“重载”我要导入的assertEquals方法一样,但我的私有非静态方法似乎是隐藏静态导入的方法。我还尝试将我的方法变成公共和静态(所有排列),但没有成功——我不得不重命名它 为什么它会这样?我在文档中找不到任何有关此行为的引用。重载和覆盖在继承树中起作用。但

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

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

我希望代码的行为就像我正在“重载”我要导入的
assertEquals
方法一样,但我的私有非静态方法似乎是隐藏静态导入的方法。我还尝试将我的方法变成
公共
静态
(所有排列),但没有成功——我不得不重命名它


为什么它会这样?我在文档中找不到任何有关此行为的引用。

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

如果您想在自己的assertEquals方法中使用junit的assertEquals,则必须使用类名来限定它,例如Assert.assertEquals

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

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

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

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


我建议您
导入org.junit.Assert
并使用
Assert.assertEquals(…)

您观察到的调用。当java中的两种类型具有相同的简单名称时,其中一种类型将隐藏另一种类型。因此,阴影类型不能由其简单名称使用

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

现在让我们读一下:

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


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

这很有意义。假设javac做了您想做的事情,它现在选择您的
assertEquals(MyObj,MyObj)
方法。如果明天
org.junit.Assert
添加了自己的
assertEquals(MyObj,MyObj)
方法会怎么样?调用
assertEquals(mo1,mo2)
的意义在不知不觉中发生了巨大的变化

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

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

如果在编译时,毫无疑问要开发该方法所属的类,那么该类明天仍有可能重载该方法,从而更改调用的目标方法。
然而,因为这是由同一个类完成的,我们可以让它负责。例如,如果
org.junit.Assert
决定添加一个新的
assertEquals(MyObj,MyObj)
方法,则必须注意,以前对
assertEquals(Object,Object)
的一些调用现在被重新路由到新方法,它必须确保没有任何语义更改会破坏调用站点。

是什么阻止您更改内部方法的签名(甚至名称)?@DomSelvon,更改签名没有帮助。关于方法名称-没有什么能阻止我-现在的问题纯粹是为了知识(已经更改了名称),这似乎是最好的答案,而不更改自定义方法的名称。这种风格明确了方法的来源。但就清晰性而言,重要的问题是“它能做什么?”在这方面,你在没有澄清任何事情的情况下,几乎将角色数量增加了一倍。正如多卢斯指出的那样,这是真实的,而不是隐藏的,因为,
Assert.assertEquals
方法没有被继承。这看起来确实是这样的——尽管我不得不承认,在阅读了您的解释和规范之后——我仍然不明白为什么一个具有特定签名的方法会影响另一个方法。您能试着解释一下在这种情况下您期望的行为吗?这两个方法都有相同的简单名称,编译器无法神奇地猜测您尝试调用的方法(私有方法和静态导入方法),因此它必须依赖阴影规则来选择一个。或者您的意思是您仍然不明白为什么它更喜欢一个方法而不是另一个?这只是仔细阅读并应用规范中的规则。总的来说,你可以说它更喜欢本地的东西,然后是类,然后是继承的,然后是导入的,然后是按需导入的。我的期望是它将允许方法重载。为什么
assertEquals(int,String,HTTPRequest)
shadow
assertEquals(Object,Object)
。这是没有意义的拒绝程序员的东西,可以很容易地区分好问题。这让我有点惊讶,但再多想想,这是有道理的。一个类中的方法重载已经够复杂了,在类之间这样做?大笑。我能为您提供的关于这个决定的唯一来源是:Java编程的主要特征
import static org.junit.Assert.assertEquals;
private void assertEquals(MyObj o1, MyObj o2)
{
    assertEquals(o1.getSomething(), o2.getSomething());
    assertEquals(o1.getSomethingElse(), o2.getSomethingElse());
    ...
}