为什么我不能“静态导入” “等于” Java 中的方法?
我喜欢在这里使用这个方法:
org.apache.commons.lang.ObjectUtils.equals(Object object1, Object object2)
唯一的缺点(例如与 Google Guava 相比)是我无法静态导入该方法。即,这是无用的:
import static org.apache.commons.lang.ObjectUtils.equals;
...因为我的 Eclipse 编译器在编写时不会正确链接该方法
equals(obj1, obj2);
错误是:
Object 类型中的方法 equals(Object) 不适用于参数 (..., ...)
这是为什么?如果任何超类型中存在具有相同名称(但签名不同)的方法,我的静态导入方法是否不适用? JLS 中有正式规定吗? 或者某些 Eclipse 编译器问题?
更新
这也不起作用:
import static org.apache.commons.lang.ObjectUtils.defaultIfNull;
public class Test {
void test() {
defaultIfNull(null, null);
// ^^ compilation error here
}
void defaultIfNull() {
}
}
javac 错误消息:
Test.java:5: defaultIfNull() in Test cannot be applied to (<nulltype>,<nulltype>)
defaultIfNull(null, null);
^
1 error
I like using this method here:
org.apache.commons.lang.ObjectUtils.equals(Object object1, Object object2)
The only drawback (compared to Google Guava, for instance), is that I cannot static import the method. I.e. this is useless:
import static org.apache.commons.lang.ObjectUtils.equals;
... as my Eclipse compiler will not correctly link that method when writing
equals(obj1, obj2);
The error is:
The method equals(Object) in the type Object is not applicable for the arguments (..., ...)
Why is that? Is my statically imported method not applicable if there is a method with the same name (but not the same signature) in any of the super types? Is this formally specified in the JLS? Or some Eclipse compiler issue?
UPDATE
This doesn't work either:
import static org.apache.commons.lang.ObjectUtils.defaultIfNull;
public class Test {
void test() {
defaultIfNull(null, null);
// ^^ compilation error here
}
void defaultIfNull() {
}
}
javac error message:
Test.java:5: defaultIfNull() in Test cannot be applied to (<nulltype>,<nulltype>)
defaultIfNull(null, null);
^
1 error
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
碰撞实际上是与
Object.equals()
发生的。所有类均继承自Object
,因此具有导致此冲突的Object.equals()
方法。您是按姓名导入,而不是按签名导入。因此,您实际上无法导入名为
equals
的静态方法。或者更确切地说,您可以导入它,但不能使用它。我确实同意这应该有效。(我的评论是我自己的答案。)
The collision is actually with
Object.equals()
. All classes are inherited fromObject
and therefore have theObject.equals()
method which leads to this collision.You're importing by name, not by signature. You actually can't import a static method named
equals
because of this. Or rather, you can import it, but not use it. I do agree that this should work though.(Made my comments my own answer.)
根据 Java 语言规范
因此,在您的情况下,上面提到的第 2 点是您收到编译时错误的原因。因此,即使方法签名不同,如果名称相同,也会出现编译时错误。
静态导入 JSR 和 JLS
As per Java Language Specification
So in your case its point 2 mentioned above is the reason you are getting compile time error. so even if method signatures are different if there names are same its a compile time error.
static import JSR and JLS
JLS 15.12.1。确定方法可以“在范围内”的两个原因:
现在有两个因素导致了令人惊讶的结果:
这个“否则”意味着搜索范围仅限于尝试两个分支中的任何一个。
首先,我们必须决定是搜索封闭类型还是使用静态导入。封闭类型具有更高的优先级,我们找到了正确名称的方法(Test.defaultIfNull()),搜索到此结束。当后来我们发现这个方法不兼容时,就没有办法再尝试静态导入了。
这种情况在 JLS 中并不罕见,方法查找的其他问题也是分阶段组织的,其中一个阶段中的部分匹配可能会妨碍在后续阶段中找到更好的匹配。固定数量与可变数量匹配是这个概念的另一个例子。在所有情况下的效果是编译器不会搜索整个可能的解决方案空间,但在做出某些决定后,整个分支将被切断并且永远不会被访问。
从上面可以得出一个经验法则:重载只能在相同类型层次结构的方法之间进行选择,而不能在继承无关的类型的方法之间进行选择。
JLS 15.12.1. identifies two reasons, why a method can be "in scope":
Now two factors contribute to the surprising result:
This "otherwise" implies that the search scope is restricted to only trying either of the two branches.
First we have to decide whether we search an enclosing type or using a static import. Enclosing type has higher priority, we find a method of the correct name (Test.defaultIfNull()), search ends here. When later we find this method to be incompatible, there's no going back to trying the static import.
The situation is not uncommon in JLS, also other issues of method lookup are organized in phases, where a partial match in one phase may prevent finding a better match in a subsequent phase. Fixed-arity vs. variable arity matching is another example of this concept. The effect in all cases is that compilers do not search the entire possible solution space, but after certain decisions have been made entire branches are cut off and never visited.
A rule of thumb can be derived from the above: Overloading can only select among methods of the same type hierarchy, it cannot select between methods of types unrelated by inheritance.
我做了一些测试。我注意到的第一件事是,对于同名的多个方法,您只需要一个静态导入语句。
然后我注意到它在实例上下文中不起作用:
但是如果我用类自己的静态方法破坏静态导入:
它在静态上下文中工作的事实对我来说是很有意义的。但是,静态导入方法和类的已定义静态方法的解析之间似乎存在显着差异。
摘要:
我有兴趣查看 JLS 或编译器规范的一部分,该部分指定编译器对静态导入的解析以及它们如何被本地方法破坏。
I did a few tests. First thing I noticed is that you only need one static import statement for multiple methods of the same name.
Then I noticed that it doesn't work in an instance context:
But then if I clobber the static import with the class's own static method:
The fact that it works in a static context makes a reasonable amount of sense to me. However, it appears there is a significant difference between the resolution of a statically imported method and a defined static method of the class.
Summary:
I'd be interested to see the part of the JLS or a compiler spec that specifies the resolution of static imports by the compiler and how they are clobbered by local methods.
我也梳理了JLS3,没有找到明确的答案。
根据 15.12.1,首先我们需要确定声明/继承 equals 方法的单个类。这里我们有两个候选类,并且规范似乎没有解决冲突的规则。
我们可以研究一个类似的问题。简单类型名称可以引用导入类型或继承类型(超类的成员类型)。 Javac 选择了后者。这可能是因为 6.5.2 中的程序为导入提供了最低优先级。
如果同样的原则适用,导入的
ObjectUtils.equals
应该屈服于继承的Object.equals
。然后,根据 15.12.2.1,Object
中没有可能适用于表达式equals(obj1, obj2)
的equals
方法,就我个人而言,我' d 更喜欢 import 优先于继承,因为 import 更接近。它还稳定了名字的含义。在当前方案中,假设
Object
没有equals
方法,则表达式equals(obj1, obj2)
引用ObjectUtils .等于
;现在假设Object
添加了equals
方法,这是一个完全无辜的举动,突然子类无法编译。更糟糕的情况是:新的 equals 方法具有兼容的签名;子类仍然可以编译,但表达式的含义悄然发生了变化。I also combed through JLS3 and couldn't find a definitive answer.
per 15.12.1, first we need to determine the single class where the
equals
method is declared/inherited. Here we have two candidate classes, and the spec doesn't seem to have a rule to resolve the conflict.We can investigate a comparable problem. A simple type name may refer to both an imported type, or an inherited type (a member type of the super class). Javac picks the latter. This is probably because of the procedure in 6.5.2, which gives imports the lowest priority.
If the same principle applies, the imported
ObjectUtils.equals
should yield to inheritedObject.equals
. Then per 15.12.2.1, there is noequals
method inObject
that's potentially applicable to the expressionequals(obj1, obj2)
Personally, I'd prefer that import has precedence over inheritance, because import is closer. It also stabilizes the meaning of a name. In the current scheme, suppose
Object
doesn't have anequals
method, the expressionequals(obj1, obj2)
refers toObjectUtils.equals
; now supposeObject
adds theequals
method, a totally innocent move, suddenly the subclass doesn't compile. An even worse scenario: the newequals
method has a compatible signature; the subclass still compiles, yet the meaning of the expression silently changes.这并不是真正的答案(在某种程度上只是更多问题)。这证明编译器确实导入了带签名的方法。
这或许也有关系。内部类中的方法“隐藏”外部类中具有不同签名的静态方法。
http://ideone.com/pWUf1
看起来编译器有不同的位置来查找方法并检查他们一一搜索,但仅按名称进行搜索,导致搜索过早终止。
This isnt really an answer (just more questions in a way). This is proof that the compiler does import the methods with signature.
This may also be related. A method in an inner class 'hiding' a static method in the outer class with a different signature.
http://ideone.com/pWUf1
It looks like the compiler has different places where to look for methods and it checks them one by one but only searches by name leading to a premature termination of the search.
这是与 java.awt 的方法冲突,您需要像这样引用该包:
It's a method collision with java.awt, you need to reference the package like this:
事实上,我认为这更多的是 Eclipse 问题而不是其他问题。
如果您使用接收两个参数的 equals() 的重载版本,则不应与默认的 Object.equals() 发生冲突。
Eclipse 中有一些技巧,您可以使用它们来识别静态导入:
1 - 添加静态类型以组织导入
转到:
然后单击“New Static”,然后单击“Types”,然后选择您的类(在本例中为 org.apache.commons.lang.ObjectUtils)
仍在“组织导入”面板上时,取消选择
(不要忘记这一点,这很重要)
2 - 将类型添加到内容辅助
转到:
然后单击“New Type”,然后选择您的类(在本例中,再次选择 org.apache.commons.lang.ObjectUtils)
现在,您应该能够在方法中的任何位置按 Ctrl+Space 并获得“equals(Object,Object)”方法作为可能的内容。如果您选择该方法,Eclipse 应该自动插入 equals 的静态导入。
Actually I think this is more of an Eclipse issue than any other thing.
If you are using an overloaded version of equals() that receives two arguments, there should be no collision with the default Object.equals().
There are a couple of tricks in Eclipse that you can use to get it to recognize the static import:
1 - Add the static type to Organize Imports
Go to:
then click on "New Static", then "Types", then choose your class (in this case org.apache.commons.lang.ObjectUtils)
While still on the Organize Imports panel, deselect the
(do not forget this, it's important)
2 - Add the type to Content Assist
Go to:
then click on "New Type", then choose your class (in this case, again, org.apache.commons.lang.ObjectUtils)
Now with this you should be able to Ctrl+Space anywhere on your method and get the "equals(Object,Object)" method as possible content. If you choose that method, Eclipse should automatically insert the static import for equals.