繁体   English   中英

调用泛型方法时未指定的类型参数

[英]Unspecified type parameter when calling generic method

假设我们有以下通用类:

public class GenericClass<U> {
    private U value;

    public GenericClass(U value) {
        this.value = value;
    }
}

和其他一些类MyClass中的以下通用方法:

public <T extends BT, BT> void genericMethod(T arg) {
    Object genericClass = new GenericClass<BT>(arg);
}

如果调用,BT类型参数将获得哪个值

genericMethod("text");

一些注意事项:

上面的代码编译时没有错误或警告,这对我来说似乎很奇怪。 反编译(通过IntelliJ IDEA 2016)显示以下代码:

public <T extends BT, BT> void genericMethod(T arg) {
    new MyClass.GenericClass(arg);
}

请注意,新GenericClass<BT>(arg)new GenericClass(arg)因为后者等效于new GenericClass<T>(arg) (类型推导),尽管T extends BT ,但它们是不同的类型, GenericClassGenericClass可能具有内部逻辑,其中确切的类型名称起着重要的作用(例如,在某些映射中用作字符串键等)。 因此,对我而言,奇怪的是,编译器为何默默地使用类型推导而不是产生一些警告(甚至可能是错误)来说明未指定BT类型参数。 也许我想不到。 对于Java中的泛型来说很重要,但是...

该答案的第一部分将解决您问题的类型推断部分

在您的示例中唯一自动推断类型的地方是在调用genericMethod

genericMethod的定义声明了两个泛型类型参数: an unbound BTT which should be a subclass of BT

类型T将根据Java语言规范第18.2.4节中指定的规则进行推断:

形式为‹S = T›(其中S和T为类型)的约束公式可简化为:

...

否则,如果T是一个推断变量,α,而S不是原始类型,则约束将减少到边界S =α。

在您的示例中,您提供了String类型的对象作为T类型的参数。 根据上述规则,将推断出T等于String

现在T是固定的,推断将以BT 通过以下第18.3.1节推断出此类型,该指出类型的表达式:

T extends BT, T == String

暗示

String extends BT

这种关系允许编译器将BT绑定到String ,因此您将得到以下隐式调用:

genericMethod<String,String>("text")

希望这能使事情顺利进行。

要回答问题的第二部分:

尽管T扩展了BT,但它们是不同的类型,并且GenericClass可能具有内部逻辑,其中确切的类型名称起着重要的作用(例如,在某些映射中用作字符串键等)

在不添加更多约束的情况下,编译器会将T视为与BT等效,并允许您仅调用定义为BT类型一部分的方法。

除非您使用反射做一些很奇怪的事情,否则代码不应依赖于类型实参的运行时值。 当前的GenericClass并不是十分有用,因为U没有任何约束,因此编译器将只允许您执行对所有对象都有效的操作。 在这种情况下,您可以将U视为Object

根据您问题的这一部分

GenericClass可能具有内部逻辑,其中确切的类型名称起着重要的作用(例如,在某些映射中用作字符串键等)。

我认为关于如何推断这些类型可能会有些困惑。 重要的是要意识到,GenericClass将包含的类型是您传入的内容的运行时类型。任何依赖于确切类型的,您可能在内部进行的操作(尽管通常您实际上不应该这样做)都可以正常工作。

总体而言,在编译时进行的类型检查对您来说似乎有点松散(尤其是例如来自C ++的情况)。 在这个问题的答案中有一些有趣的讨论。 Java泛型-类型擦除-何时以及何时发生

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM