未指定类型参数

未指定类型参数

问题描述:

假设我们有以下的通用类:未指定类型参数

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,这些都是不同类型和GenericClass可能具有内部逻辑,其中确切类型名称发挥重要作用(例如,在某些地图等中用作字符串键)。所以对我来说,很奇怪为什么编译器默默地使用类型推导而不是产生一些警告(或者甚至错误),指出BT类型参数没有被指定。也许我错过了水手。关于Java泛型重要的,但是......

这个答案的第一部分将调用时解决您的问题

唯一的地方,一类是自动在你的例子是推断出来的类型推断部分genericMethod

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

类型T将根据Java language specification section 18.2.4指定的规则进行推断:

形式,其中S和T是类型的约束公式,减小如下:

...

否则,如果T是推理变量,α和S不是原始类型,则约束减少到边界S =α。

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

现在T是固定的,推断将继续进行BT。这种类型的由以下section 18.3.1它说,类型的表达式推断:

T extends BT, T == String

意味着

String extends BT

这种关系允许编译器结合BTString,因而你结束了以下隐含电话:

genericMethod<String,String>("text") 

希望这可以清理一些东西。

为了回答你问题的第二部分:

虽然牛逼扩展BT,这些都是不同的类型,以及GenericClass 可能有内部逻辑,其确切的类型名称起着重要 作用(例如,在某些地图等中用作字符串键)

无需添加更多的约束,编译器会将T等同于BT,并允许您呼叫只定义为BT类型的一部分的方法。

除非你使用反射做了非常奇怪的事情,否则代码不应该依赖于类型参数的运行时值。 现在的GenericClass并不是很有用,因为U没有任何约束,所以编译器将允许你只做对所有对象都有效的东西。 在这种情况下,您可以考虑UObject相同。

+0

谢谢你的回答。 什么是“推理变量”?你可以在我的代码示例中指向这样的吗?在genericMethod()声明中,我只看到两个*类型变量*(T和BT)和一个常用变量(arg)。 我在第18.1.1节中读到了以下内容:_“推理变量是类型的元变量 - 也就是说,它们是允许抽象推理类型的特殊名称,为了将它们与类型变量区分开来,推理变量被表示与希腊字母,主要是α“_。然而,它并没有为我清楚这个词。 –

+0

**你写:** _string延伸BT 这种关系允许编译器BT绑定到字符串,所以你结束了以下隐含调用: genericMethod ( “文本”)_ - 我不明白为什么它允许这样做:“字符串扩展BT”与“BT ==字符串”不一样! **您也可以编写:** _如果不添加更多约束,编译器会将T等同于BT,并允许您仅调用定义为BT类型一部分的方法._ - 同样在这里!编译器会更好地产生BT在任何地方都不使用的错误。 –

+0

**您写:** _目前的GenericClass并不是非常有用[...]。你可以认为U在这方面与Object._ 相同 - 我同意:这个样本是一个太蒸馏的样本。在我的真实项目中,_JAXBElement_站在这里(代替GenericClass)。 –

基于你的问题,这部分

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

我想可能会有一些混淆,关于如何推断这些类型。重要的是要认识到,GenericClass将包含的类型是任何你传入的运行时类型。依赖于确切类型的任何东西,你可能在内部做的事情(尽管通常你不应该这样做)将工作得很好。

总的来说,编译时完成的类型检查可能对你来说看起来有些松散(特别是如果你来自C++)。关于这个问题的答案有一些有趣的讨论。 Java generics - type erasure - when and what happens