Pool of constants

  • Tutorial
Many people know that every .class file has a wonderful data structure called a constant pool. But not every Java developer, looking at the source, can even roughly estimate how many constants will be created in the pool.

Take, for example, the following code:

System.out.println("Hello World!");

It translates into three bytecode instructions: getstatic (to load the static field System.out), ldc (to load the constant string “Hello World!”) And invokevirtual (to execute the println virtual function). Try to figure out how many constants you need for this code to work.

It turns out that this line uses 14 constants, which can be schematically depicted as follows:

As we can see, most constants are references to other constants. Each constant has a type, value and number by which it can be referenced. Here are the basic types that don't reference anything:
  • Integer is an integer. They are referenced from the code where the number was required. The numbers from -32768 to 32767 the compiler does not add here: they can be explicitly specified in the code using the instructions iconst_ x , bipush and sipush.
  • Long is a long integer. For historical reasons, it occupies two positions in the pool of constants (that is, the next constant has two more numbers). You can save only on 0L and 1L with lconst_ x ; 2L is already in the pool.
  • Float - single precision material. Special instructions fconst_ x are for 0.0f, 1.0f and 2.0f; the remaining numbers used are in the pool.
  • Double - real double precision. Like Long, it occupies two positions in the pool. Only the numbers 0.0 and 1.0 can be used without a pool using the dconst_ x instructions .
  • Utf8 is a Utf8 encoded string literal. The maximum length does not exceed 65535 bytes (characters, of course, may be less). These literals are most often referenced from other constants.

Here are some of the reference types:
  • String is a string. Contains a reference to a constant like Utf8. If you use a string in your code, you are referring to a constant of type String. It looks like an extra entity, but it is.
  • NameAndType - a constant that describes the name and type of the field or method. Contains two references to Utf8 constants with name and type.
  • Class is a constant that describes the name of a class or interface. Contains a reference to the Utf8 constant with the internal class name.
  • Fieldref is a constant that describes a particular field of a particular class. Contains a reference to the Class constant and a link to the NameAndType constant.
  • MethodRef, InterfaceMethodRef - constants that describe a specific method of a class or interface. Contains references to the Class constant and the NameAndType constant.

To access a field, you need not only its name, but also the full name of the class where the field is declared, as well as the type of the field. To access a method, you need the class, name, and signature of the method. Fortunately, the whole signature is encoded in one line, regardless of the number of method parameters: primitive types are encoded with one letter (for example, D = double), objects with the letter L, followed by the full class name and semicolon, and one level of the array adds square bracket. Argument types are in parentheses, followed by the return type (V is void). For example, (IDLjava/lang/Thread;)Ljava/lang/Object;this method will have a signature :
Object m(int i, double d, Thread t) {...}

From the fact that a precise signature is required to refer to a method, developers sometimes run into NoSuchMethodError. Let's say you changed the return type of the method to a more specific one. Then the calls to this method from other classes remain the same, and the compiler will not recompile these classes, because the source files have not changed. However, if you try to call this method at runtime, the Java machine will look for the old signature.

If you automatically generate Java code, remember that the maximum constant number in the pool does not exceed 65535, after that there will be a compilation error. This is not such a large number, given the huge number of links and the fact that long and double occupy two positions. Knowing the pool device will help you control its filling when generating code.

For more information on the constant pool device, see §4.4 of the Java Virtual Machine specification.

Also popular now: