在通用签名的规范中,ClassSignature的形式如下
ClassSignature:
[TypeParameters] SuperclassSignature {SuperinterfaceSignature}
TypeParameters:
< TypeParameter {TypeParameter} >
TypeParameter:
Identifier ClassBound {InterfaceBound}
ClassBound:
: [ReferenceTypeSignature]
InterfaceBound:
: ReferenceTypeSignature
因此,可以省略类型参数的超类边界(此处的一些示例)。
如果我有一个类声明public class A<T, LFooBar>
,Java编译器会生成签名<T:Ljava/lang/Object;LFooBar:Ljava/lang/Object;>Ljava/lang/Object;
。
IUC,可以省略类绑定,在这种情况下,签名将被<T:LFooBar:>Ljava/lang/Object;
。
解析该短签名需要向前看第二个:
,以便知道T:LFooBar:
是两个类型参数,而不是一个类型参数T
类绑定FooBar
。
也许在实践中,只有在有接口绑定的情况下才能删除类绑定?对于public class A<T extends Comparable<? super T>>
,javac 生成签名<T::Ljava/lang/Comparable<-TT;>;>Ljava/lang/Object;
。但我想我不能依赖这个假设。
我是不是误会了什么?
如果你仔细观察,唯一可以遵循省略ReferenceTypeSignature
的是Identifier
或>
。由于ReferenceTypeSignature
必须以[
开头或以;
结尾,并且标识符不能包含这些字符,而标识符后必须跟有:
,不能显示为类型签名,因此这些选项之间没有歧义。
请注意,标识符可以以>
开头,因此您需要提前寻找冒号以确定您是否在末尾TypeParameters
。但这是一个单独的问题。
我不确定 JVM 是如何实现它的,但一种可能的方法是:
- 检查第一个字符。如果是 [,则具有类型签名。如果>,请提前扫描第一个 [、; 或 :。如果您看到的第一个是 :,则表示您具有标识符,否则您具有类型结束参数。
- 否则,请提前扫描第一个 ;或 :。如果是 :,则您有一个标识符,否则您有一个类绑定。
编辑:签名中的标识符不能包含>
,因此请忽略该位。(它们也不能包含:
,这是另一个潜在的歧义来源)