当前位置: 首页 > 面试题库 >

与Java方法调用中的类型参数有关的问题

祖利
2023-03-14
问题内容

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"
}

我有几个问题:

  1. 谁能提出Java允许这些冗余类型参数的正当理由?接受它们无害后,在我看来,编译器仍然可以并且应该抓住它们。

  2. 仅当带有类型实参的方法调用以“ this”为前缀时,该代码才会编译。否则,您将收到“表达式的非法开始”错误。那是个错误吗?不应有任何与“ this”一起使用的明确方法调用。也可以不用“这个”。

(这些问题的催化剂是甲骨文对我针对某人在此处提出的一个有趣的Java问题创建的错误报告的回应。)

更新2015年9月18日

  1. 我针对Oracle的此问题提出了错误JDK-8098556。这是他们的回应:

这不是问题 ;使用与普通方法相同的规则检查方法引用-请注意,对于普通方法,您始终可以提供冗余类型参数:

void m() { }
this.<String>m(); //legal

按照15.13:方法(和构造函数)引用只是继承了此行为:“”如果方法引用表达式的形式为ReferenceType ::
[TypeArguments]标识符,则可能适用的方法是要搜索的具有适当类型的成员方法名称(由标识符提供),可访问性,统一性(n或n-1)和类型自变量arity(从[TypeArguments]派生),如§15.12.2.1中所指定。”

  1. 由于该答复确认了 TAsk 在下面已经提供的信息(包括引用JLS的相关部分),因此我接受了该回答。

问题答案:

以下是该 方法 的方法调用的:

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 适用于提供显式类型参数的调用。确实,这可能是适用的。在这种情况下,类型参数将被简单地 _ 忽略_ 。

它说 确实,它 可能 是适用的(在运行时)

此外,

该规则源于 兼容性和可替代性原则。 由于接口或超类的生成可以独立于其子类型,因此 我们可以用非泛型方法覆盖泛型方法。
但是,重写(非泛型)方法必须适用于对泛型方法的调用,包括显式传递类型实参的调用。
否则,该亚型将无法替代其生成的超型。



 类似资料:
  • 我刚开始使用Mockito,我正在验证某个方法应该用特定的参数调用,而所有的值类型参数(int、String、enum等)都可以验证,但引用/类类型参数似乎没有,下面是一个示例 那么,我如何将引用对象传递到我的输入方法中,并在这里将其模拟为我的内部方法的返回值呢?顺便说一句,如果我的方法只包含值类型参数,它将工作...

  • 我遇到了一个家庭作业的麻烦,创建一个调用另一个类的方法的类。给我们下一课: 然后给出以下提示: 实现一个类Portfolio。这个类有两个对象,checking和savings,类型为BankAccount。实现四种方法: 公用无效存款(双倍金额,字符串帐户) 公开无效提取(双倍金额,字符串帐户) 公有作废转账(双倍金额,字符串账户) 公共双getBalance(字符串帐户) 这里的帐户字符串是“

  • 问题内容: 您认为可以创建类似的东西吗? 问题答案: 是的你可以。 用法示例:

  • 问题总结:我想传递一个带有类型参数(如

  • 问题内容: 问题摘要: 我想将具有类型参数(例如)的类作为类型参数传递给泛型方法。 假设我有一个方法: 当然,此方法对于任何类型的类都可以正常使用。我可以这样调用该方法,例如: 问题: 我发现我不能这样做: 从句法上讲,这显然是无效的。但是,我不确定如何实现这样的目标。我当然可以通过,但是泛型类型的添加使其在语法上不再有效,并且我想不出解决方法。 唯一的直接解决方案是这样的事情(看起来很愚蠢):

  • 问题内容: 在C#中,我实际上可以这样做: 但是由于某种原因,我无法使其在Java中工作。 我要做的是在超类上创建一个静态方法,以便可以将子类转换为XML。 问题答案: 称为: 或更明确地: 更令人困惑的是,您可以拥有既构造泛型类型又具有泛型参数的构造函数。不记得该语法,也从未在愤怒中使用过它(无论如何,最好还是使用静态创建方法)。 强制转换是不安全的,并且您不能编写T.class。因此,将T.c