我正在使用 Java语言规范,第三版阅读Java中的泛型。在“4.6 Erasure”部分中定义了类型擦除。关于类型变量的擦除,它说
类型变量(第4.4节)的擦除是其最左边界的擦除。
这让我对类型变量和类型参数之间的区别感到困惑,因为“4.4 Type Variables”部分的定义为:TypeParameter: TypeVariable TypeBound
其中绑定是可选的。但也许您可以使用它出现的类型参数来识别类型变量,因为类型变量只能(?)出现在一个“上下文”中,然后类型变量的最左边界限被定义为其对应的类型参数的最左边界限或{ {1}}如果类型参数中没有显式绑定?
答案 0 :(得分:6)
如果没有为类型变量给出绑定,则假定为Object。
在您的链接中找到。这意味着给定FirstClass<T extends String>
和SecondClass<V>
即可:
FirstClass
类型参数:T extends String
。输入变量:T
。类型绑定:String
。SecondClass
类型参数:V
类型变量:V
。类型绑定:默认为Object
。 修改:类型参数,类型变量和类型绑定我不是指语法规则,但这个概念。因此,extends
只是关键字。
关于最左边的边界,你可以在同一个链接中找到答案,第一个引用后的两个句子:
绑定中类型的顺序只是重要的,因为类型变量的擦除由其边界中的第一个类型确定,并且类类型或类型变量可能只出现在第一个位置。
答案 1 :(得分:1)
TL; DR - 背景就是一切!
非正式地,&#34; 类型变量&#34;和&#34; 类型参数&#34;可互换地用作彼此的同义词[even by Gilad Bracha — the creator of Java's Generics implementation]。
然而,正式地,the JLS明确地将它们描述为两个不同的 - 但紧密相关的 - 抽象。
在过去,我自己也有类似的问题,关于术语&#34; 类型参数&#34;的不太明确的用法。和&#34; 类型变量&#34;在许多关于泛型的文献中。
根据我对the more-recent Java 8 JLS的解释, TypeParameter
出现在参数化类中。或方法的类型参数部分[声明的<>
部分]。
The JLS says, "A type variable is introduced by the declaration of a type parameter..."。我认为这意味着,为了使用 TypeVariable
,您必须先填写方法[或类&#39; ]按照为声明 TypeParameter
...
TypeParameter:
{TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
Annotation
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
AdditionalBound:
& InterfaceType
阅读the above syntactic production for TypeParameter
和this one for TypeVariable
...
TypeVariable:
{Annotation} Identifier
...我将这两个产品解释为,如果 T
具有[em> T
的上下文中使用了标识符 TypeBound
或可以]之后 T
,然后 TypeParameter
是 T
。或者,如果在不允许 TypeBound
的上下文中使用标识符 T
,则 TypeVariable
是 TypeParameter
。
我认为 TypeParameter
类似于方法声明的 形式参数 。
当the JLS says, "A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies",我将其解释为在类型参数部分中声明 class Foo {
private Bar bar;
}
class Boff extends Foo { }
时,也类似于声明可以随后使用的类作为一个实例变量的参考类型 - 某种意义上的 。
我的意思是,为了让以下内容合法......
Bar
..然后您必须先 介绍 Foo
类型的声明,然后才能在 {{1}的正文中使用} 的。类似地,必须首先声明类型参数 <T extends Foo>
,以使以下内容合法......
class Baz<T extends Foo> { /* The TypeParameter that "introduces" T comes first */
private T quux; /* now T is a TypeVariable in this context */
/* <U extends Number> is the TypeParameter that "introduces" the TypeVariable, U */
public <U extends Number> List<? super U> m( Class<U> clazz ) throws Exception { /* <U extends Number> 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<Boff> buzz = new Baz<>();
... Boff
菱形内的 <>
,既不是类型变量 也不是类型参数 。它是类型参数 。