类型变量和参数的定义
我正在使用Java语言规范第三版阅读Java中的generics。 在“ 4.6擦除 ”部分中,定义了擦除类型。 关于类型变量的擦除,它说
类型变量(第4.4节)的擦除是其最左边界的擦除。
这让我对类型变量和类型参数之间的区别感到困惑,因为“ 4.4类型变量 ”部分具有以下定义: TypeParameter: TypeVariable TypeBound
,其中bound是可选的。 但也许您可以使用它出现的类型参数来识别类型变量,因为类型变量只能(?)出现在一个“上下文”中,然后类型变量的最左边界限被定义为其对应的类型参数或Object
的最左边界限如果类型参数中没有显式绑定?
如果没有为类型变量给出绑定,则假定为Object。
在您的链接中找到。 这意味着给定FirstClass
和SecondClass
你会得到:
- 类:
FirstClass
类型参数:T extends String
。 类型变量:T
。 键入Bound:String
。 - 类:
SecondClass
类型参数:V
类型变量:V
。 类型绑定:默认为Object
。
编辑:按类型参数 , 类型变量和类型绑定我不是指语法规则,而是概念。 因此, extends
只是关键字。
关于最左边的边界,你可以在同一个链接中找到答案,第一个引用后的两个句子:
绑定中类型的顺序只是重要的,因为类型变量的擦除由其边界中的第一个类型确定,并且类类型或类型变量可能仅出现在第一个位置。
TL; DR – 上下文就是一切!
非正式地,“ 类型变量 ”和“ 类型参数 ”可互换使用,作为彼此的同义词[ 甚至是Gilad Bracha– Java的generics实现的创建者 ]。
然而,forms上, JLS明确地将它们描述为两种不同但又密切相关的抽象。
在过去,我自己也有类似的问题,关于generics的许多文献中关于“ 类型参数 ”和“ 类型变量 ”这两个术语的使用不那么明确。
根据我对更新的Java 8 JLS的解释 , TypeParameter
出现在参数化类’或方法的类型参数部分[ 声明的<>
部分 ]中。
JLS说,“ 类型变量是由类型参数的声明引入的 ……” 。 我将其解释为,为了使用TypeVariable
,您必须首先按照为声明TypeParameter
指定的规则填写方法的[ 或类’ ]类型参数部分…
TypeParameter: {TypeParameterModifier} Identifier [TypeBound] TypeParameterModifier: Annotation TypeBound: extends TypeVariable extends ClassOrInterfaceType {AdditionalBound} AdditionalBound: & InterfaceType
阅读TypeParameter
的上述语法生成,以及TypeVariable
这个 …
TypeVariable: {Annotation} Identifier
…我将这两个产品解释为如果标识符T
在T
具有[ 或可能具有 ] TypeBound
的上下文中使用,那么T
是TypeParameter
。 或者,如果在不允许TypeBound
的上下文中使用标识符T
,则T
是TypeVariable
。
我认为TypeParameter
类似于方法声明的forms参数 。
当JLS说“ 一个类型变量是一个在类,接口,方法和构造函数体中用作类型的非限定标识符 ”时 ,我将其解释为在类型参数部分中声明一个TypeParameter
,也类似于在某种意义上 ,声明一个类可以随后用作实例变量的引用类型。
我的意思是,为了让以下内容合法……
class Foo { private Bar bar; } class Boff extends Foo { }
..然后你必须首先介绍 Bar
类型的声明,然后才能在Foo
的主体中使用它。 类似地,必须首先声明类型参数
,以使以下内容合法……
class Baz { /* The TypeParameter that "introduces" T comes first */ private T quux; /* now T is a TypeVariable in this context */ /* is the TypeParameter that "introduces" the TypeVariable, U */ public List super U> m( Class clazz ) throws Exception { /* is the TypeParameter */ U u = clazz.newInstance( ); /* U is a TypeVariable in this context */ /*...*/ List super U> list = new LinkedList<>(); /* U is a TypeVariable in this context; just like it is in this method's return type */ /*...*/ list.add( u ); /*...*/ return list; } }
如果我被允许更具体……
Baz buzz = new Baz<>();
… <>
菱形内的Boff
既不是类型变量也不是类型参数 。 这是一个类型参数 。