A class file writes types as short strings in Utf8 entries. A descriptor gives the type the JVM works with: the erased type, with no generics. A signature, kept in the Signature attribute from version 49.0, gives the generic type as written in the source, for the compiler and for reflection. The JVM itself never checks signatures.
Field descriptors
A field descriptor is the type of a field, a local variable, a parameter or a return
value. It is one of these, and an array type puts one [ in front for each
dimension:
| Descriptor | Java type | Slots |
|---|---|---|
B | byte | 1 |
C | char | 1 |
D | double | 2 |
F | float | 1 |
I | int | 1 |
J | long | 2 |
S | short | 1 |
Z | boolean | 1 |
LClassName; | an instance of the class, named in internal form: Ljava/lang/String; is String | 1 |
[type | one array dimension: [I is int[], [[Ljava/lang/Object; is Object[][] | 1 |
The slots column is how many local variable slots and operand stack places a value of the type takes. An array type has at most 255 dimensions.
Method descriptors
A method descriptor is the parameter types in brackets, then the return type, which
may be V for void:
MethodDescriptor: ( {FieldDescriptor} ) ReturnDescriptor
ReturnDescriptor: FieldDescriptor | V
| Descriptor | Method |
|---|---|
()V | void m() |
([Ljava/lang/String;)V | void main(String[] args) |
(IDLjava/lang/Thread;)Ljava/lang/Object; | Object m(int i, double d, Thread t) |
(JJ)I | int compare(long a, long b) |
The descriptor does not include this, nor the method’s name or class.
The parameters may take at most 255 slots, counting this for instance
methods: (IDLjava/lang/Thread;)Ljava/lang/Object; takes 1 + 2 + 1 = 4
slots, and 5 with this.
Signatures
Signatures add what erasure drops: type parameters, type arguments, wildcards and
type variables. Classes, interfaces, constructors, methods, fields and record
components with generic types carry a
Signature attribute, and
local variables have them in the
LocalVariableTypeTable.
The grammar (JVM Specification §4.7.9.1), where {x} means zero or more and
[x] means optional:
JavaTypeSignature: ReferenceTypeSignature | BaseType
BaseType: B | C | D | F | I | J | S | Z
ReferenceTypeSignature: ClassTypeSignature | TypeVariableSignature | ArrayTypeSignature
ClassTypeSignature: L [PackageSpecifier] SimpleClassTypeSignature {ClassTypeSignatureSuffix} ;
PackageSpecifier: Identifier / {PackageSpecifier}
SimpleClassTypeSignature: Identifier [TypeArguments]
TypeArguments: < TypeArgument {TypeArgument} >
TypeArgument: [WildcardIndicator] ReferenceTypeSignature | *
WildcardIndicator: + | -
ClassTypeSignatureSuffix: . SimpleClassTypeSignature
TypeVariableSignature: T Identifier ;
ArrayTypeSignature: [ JavaTypeSignature
ClassSignature: [TypeParameters] SuperclassSignature {SuperinterfaceSignature}
TypeParameters: < TypeParameter {TypeParameter} >
TypeParameter: Identifier ClassBound {InterfaceBound}
ClassBound: : [ReferenceTypeSignature]
InterfaceBound: : ReferenceTypeSignature
SuperclassSignature: ClassTypeSignature
SuperinterfaceSignature: ClassTypeSignature
MethodSignature: [TypeParameters] ( {JavaTypeSignature} ) Result {ThrowsSignature}
Result: JavaTypeSignature | V
ThrowsSignature: ^ ClassTypeSignature | ^ TypeVariableSignature
FieldSignature: ReferenceTypeSignature
In a wildcard, + is ? extends, - is
? super and * alone is ?. A nested type such as
Map.Entry<K,V> inside a generic outer class uses the
. suffix. A class bound may be empty when the first bound is an
interface, giving two colons in a row.
| Signature | Kind | Java |
|---|---|---|
Ljava/util/List<Ljava/lang/String;>; | field | List<String> |
Ljava/util/Map<TK;+Ljava/lang/Number;>; | field | Map<K, ? extends Number> |
<T:Ljava/lang/Object;>(Ljava/util/List<+TT;>;)TT; | method | <T> T first(List<? extends T> list) |
<T::Ljava/lang/Comparable<-TT;>;>(Ljava/util/Collection<*>;)V | method | <T extends Comparable<? super T>> void m(Collection<?> c) |
<E:Ljava/lang/Object;>Ljava/util/AbstractList<TE;>;Ljava/util/List<TE;>; | class | class X<E> extends AbstractList<E> implements List<E> |
The source side is on the Java generics page.
In the explorer
The explorer turns descriptors back into Java types wherever it shows a member: a
field is shown as int count, a method as
public static void main(java.lang.String[]), with a variable-arity last
parameter written .... A descriptor_index whose text is not
a valid descriptor of the right kind is marked. Signatures are shown as their text.