Java 8的Java语言规范在“示例4.11-1。类型的用法”中提供了一个带有类型实参的方法调用示例:
<S> void loop(S s) {
this.<S>loop(s); // <S> is the the type argument for the method call.
}
在该示例中,提供的类型实参是有意义的,但显然用于方法调用的类型实参也可以是多余的,并且完全没有意义,并且甚至不需要涉及泛型。例如:
void m() { }
void test() {
m();
this.m();
this.<Integer>m(); // Compiles and runs OK!
this.<String, Byte, StringBuilder, Thread[], Throwable>m(); // Compiles and runs OK!
<Integer>m(); // Won't compile: "illegal start of expression"
}
我有几个问题:
谁能提出Java允许这些冗余类型参数的正当理由?接受它们无害后,在我看来,编译器仍然可以并且应该抓住它们。
仅当带有类型实参的方法调用以“ this”为前缀时,该代码才会编译。否则,您会收到“表达式的非法开始”错误。那是个错误吗?不应有任何与“ this”一起使用的明确方法调用。也可以不用“这个”。
(这些问题的催化剂是甲骨文对我针对某人在此处提出的一个有趣的Java问题创建的错误报告的回应。)
更新2015年9月18日
这不是问题;使用与普通方法相同的规则检查方法引用-请注意,对于普通方法,您始终可以提供冗余的类型参数:
void m() { }
this.<String>m(); //legal
按照15.13:方法(和构造函数)引用只是继承了此行为:“”如果方法引用表达式的形式为ReferenceType :: [TypeArguments]标识符,则可能适用的方法是要搜索的具有适当类型的成员方法名称(由标识符提供),可访问性,统一性(n或n-1)和类型自变量arity(从[TypeArguments]派生),如§15.12.2.1中所指定。”
以下是该方法的方法调用的:
JLS 15.12列出了以下方法调用方法:
MethodName ( [ArgumentList] )
(注意:这没有类型参数)TypeName.[TypeArguments] Identifier ( [ArgumentList] )
ExpressionName.[TypeArguments] Identifier ( [ArgumentList] )
Primary.[TypeArguments] Identifier ( [ArgumentList] )
super.[TypeArguments] Identifier ( [ArgumentList] )
TypeName.super.[TypeArguments] Identifier ( [ArgumentList] )
因此,在Java语言规范中,具有表达式或类型名称的方法可以具有类型实参,但请注意,在第一个方法调用中,您不能指定类型实参,因为它是非法的。
请注意,不仅this
不允许这样做,而且static
调用和super
方法调用也可以具有类型实参,并且它们是完全合法的。
static void m() { }
void test() {
ClassName.<Integer>m();//Also compiles
}
除此之外,您还会收到以下警告,
非泛型方法m()的未使用类型参数...
代表JLS 15.12.2.1的以下声明,
此子句暗示非泛型方法可能
potentially
适用于提供显式类型参数的调用。确实,这可能是适用的。在这种情况下,类型参数将被简单地忽略。
它说确实,它可能是适用的(在运行时)
此外,
该规则源于兼容性和可替代性原则。由于接口或超类的生成可以独立于其子类型,因此我们可以用非泛型方法覆盖泛型方法。但是,重写(非泛型)方法必须适用于对泛型方法的调用,包括显式传递类型实参的调用。否则,该亚型将无法替代其生成的超型。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句