Descriptors

The JVM contains descriptors for methods and fields and they are strictly required to exist.

Types

The JVM has two kinds of types, primitive and reference.

A primitive type is a built-in JVM type such as int, float, double, long and etc. A reference type is a type showing a reference to a class for example the String type used in almost every code-base is basically (oversimplification) a wrapper around a char[] since an array of characters is a string.

Reference type construction

A reference type in a descriptor needs to start with the prefix L and end with a semi-colon.

And the class name shall be in the middle.

Which means String would look like Ljava/lang/String;

This same construction goes for every single class in the JVM which means if we have a class called A it would look like LA; (assuming it is not in a directory).

If our class is in a directory we must specify it using the forward slash character and only the forward slash character, assuming our A class has been transferred to a directory such as me/reader/A then we must specify the directory in the descriptor such as Lme/reader/A;.

Primitive type construction

The JVM primitive types are very simple and are just one character for each type. This also includes void although it is illegal to be used as a parameter type or the type of a field, it is only allowed and legal to be used as a return type for a method.

Type
Descriptor

long

J

int

I

short

S

byte

B

boolean

Z

float

F

double

D

void

V

Array types

Now obviously a type may be String[] or int[] so how do we specify our type is an array?

Well we simply prefix the reference or primitive type construction with a left square bracket such as: [Ljava/lang/String; (String[]) and [I (int[]).

Array depth

In order to specify the depth of a multi-dimensional array such as int[][] we simply add more brackets respective to the depth of our array so the descriptor would be: [[I.

And this goes for any depth meaning String[][][][] would just be: [[[[Ljava/lang/String;

Method descriptor

The method descriptor is a simple string containing the return type of the method and the types of it's parameters.

It is constructed by firstly a pair of parentheses in which we specify the parameter types and outside at the end of the parentheses is where we specify the return type.

So a method with the signature: int test(int a, int b);

would have this descriptor: (II)I

we have two primitive int type characters because we take two int types as our parameters and we also return an int which results in our return type also being the int type character.

Now a method using mainly reference types for example: String test(String a, int b);

would have this descriptor: (Ljava/lang/String;I)Ljava/lang/String;

which works the exact same way as for the primitive types only the construction is different because well we don't only use primitive types anymore.

Just to close it off let's try it with the previous me/reader/A class we showed off earlier: A test(A a, A b);

would have this descriptor: (Lme/reader/A;Lme/reader/A)Lme/reader/A;

Field descriptor

Field descriptors also describe the type of a field and the only difference between them is that we don't have the parentheses anymore since well a field obviously doesn't have parameters.

A field such as: private int test = 0;

would have a descriptor only containing one character. Can you guess what the character is?

I don't know if you guessed right since this is a piece of text you're reading and not talking to an actual person but the descriptor would just be the primitive int type character I.

Now if we had a field using a reference type such as String the descriptor would just be String wrapped in the previously described reference type construction.

A field such as: private String test = "Hello!";

would have a descriptor such as: Ljava/lang/String;

Last updated