The introduction

Constant pool will be introduced in this paper and the split open a case using the mechanism, the reason that the two together, because a lot of online articles, in talking to constant pool will cache mechanism of wrapper classes, Java constant pool, indiscriminately mixed in with discussion, what is more completely to see the two as a whole, bring many problems to beginners, I just come over. Also, because the idea of a wrapper class cache is the same as a string constant pool, it’s easy to confuse, but the implementation is different.

Constant pool

Before introducing constant pools, let’s introduce the definitions of constants, literal constants, and symbolic constants.

Constants can be divided into literal constants (also known as direct constants) and symbolic constants.

Literal constants: Numbers, characters, BOOLen values, strings, etc. that can be used in a program without having to define them beforehand. Simply put, it’s determining the value itself. Such as 10, 2L, 2.3F, 3.5, “hello”, ‘a’, true, false, null, etc.

Symbolic constant: a quantity predefined in a program with an identifier whose value cannot be changed in the program. Final int a = 5;

Constant pool

Constant pool is introduced to avoid frequent creation and destruction of objects that affect system performance and realize object sharing. This is an implementation of the meta-sharing pattern.

Java constant pool

Java’s constant pool can be broken down into three categories:

  • Volume pool, compile phase)
  • Runtime constant pool (also known as dynamic constant pool, run-time)
  • String constant pool (global constant pool)

1. Class file constant pool

The class file constant pool, also known as the static constant pool, is an item of information contained in a. Class file. Used to hold the various literals and Symbolic References generated by the compiler. The constant pool is located in the.class file

literal
Symbolic reference
Direct reference
A symbolic reference can be thought of as a virtual address, and will be replaced with a direct reference only after the JVM has confirmed the address of the literal after loading the class

  • Fully qualified names of classes and interfaces
  • The name and descriptor of the field
  • The name and descriptor of the method

Constant pool information

2. Run-time constant pool

A runtime constant pool, also known as a dynamic constant pool, is a constant pool from a class file that the JVM loads into memory and stores in the method area after loading a class. That is, the constants in the runtime constant pool are basically derived from the constant pool in each class file. Runtime constant pool relative to the CLass file another important feature of the constant pool is dynamic, the Java language does not require constant must only compile time to produce, is not preset constant pool into the CLass file content can enter method area runtime constant pool, runtime might also put new constants in a pool, One feature that developers use most is the Intern () method of the String class.

When a JVM executes a class, it must go through loading, wiring, and initialization, and wiring includes three phases: validation, preparation, and parsing. When a class is loaded into memory, the JVM stores the contents of the class constant pool into the runtime constant pool. That is, each class corresponds to a separate space in the runtime constant pool, and each class file is stored in a separate location. In the parsing phase, symbolic references are replaced with corresponding direct references. Note, however, that literal String constants do not allocate space directly on the heap to create objects. The JVM maintains an additional String constant pool for String strings, so when a String constant is encountered, it looks for duplicates in the String pool and returns a reference. Otherwise, it is created and added to the string constant pool. In other words, for literal constants of type String, a global reference must be maintained in the String constant pool.

3. String literal pool (string literal pool)

The string constant pool stores literal constants of strings. To be more specific, the contents of the string constant pool are generated in the heap after class loading, validation, and preparation, and then the reference value of that string object instance is stored in the String pool (remember: The string pool holds reference values instead of specific instance objects, which are stored in a chunk of the heap. . The string pool implemented in HotSpot VM is a StringTable class, which is a hash table that holds references to the resident string (often quoted) rather than the resident string instance itself. That is, if some string instance in the heap is referenced by this StringTable, it is given the status of “resident string.” This StringTable has only one copy per HotSpot VM instance, shared by all classes.

The difference between a runtime constant pool and a string constant pool

The string constant pool is located in the runtime constant pool.

There are a lot of articles on the web that refer to string constant pools as run-time constant pools and I thought they were the same thing at first, but they’re not. The runtime constant pool and string constant pool were in the method area before HotSpot in JDK1.6, which moved the string constant pool to out-of-heap memory. The runtime constant pool provides a runtime memory space for the constant pool of each Class file. The String constant pool maintains a common pool of String literal constants for all Class files. That is, when a Class file’s constant pool is loaded into the runtime constant pool, its String literal references are consistent with the String constant pool maintenance.

Let’s do a couple of examples to understand constant pools

@example 1 Simple Example

public class Test_6 {
public static void main(String[] args) {
    String str = "Hello World!"; }}Copy the code

We use javap -v mytest. class to view the class file bytecode, javap processing can output we can understand the information. The diagram below:

@example 2 String +

Let’s look at a more complicated example

public class Test_6 {
public static void main(String[] args) {
    String str_aa = "Love";
    String str_bb = "beautiful" + " girl";
    String str_cc = str_aa+" China"; }}Copy the code

Also, look at the bytecode information in the class file:

Love
beautiful girl
China
Love China

This is because the value of str_bb is evaluated by two constants. This constant expression evaluation is evaluated by the compiler at compile time. Remember that any evaluation that can be done by the compiler is not deferred to run time. The calculation of str_cc contains the variable str_aa, and the expression calculation of the variable is calculated at run time, because the value of the variable cannot be determined during compilation, especially in multithreading, and the result is dynamically allocated by the CPU, that is, the address cannot be determined. If we take a closer look, we can see that the StringBuilder and its methods are described in the constant pool. In fact, the StringBuilder is used to evaluate the str_aa+” China” expression by calling the append() method and adding two strings. The toString() method is called and returns the result. That is, at run time, expression evaluations of String strings linked by + are done by creating a StringBuilder

@example 3 String Example of creating an object

In the following example, the value of str_bb is used to create a new object directly through new and observe the static constant pool.

public class MyTest {
public static void main(String[] args) {

    String str_bb = new String("Hello"); }}Copy the code

View the bytecode information of the corresponding class file:

Ii. Automatic packing and unpacking mechanism and cache mechanism

First, a brief introduction to the automatic packing and unpacking mechanism

1. Introduction of automatic packing and unpacking mechanism

Boxing: Can automatically convert the base type directly to the corresponding packaging type. Unpacking: automatically convert the packaging type to the corresponding basic type value;

// Common object creation method Integer a = new Integer(5); // Box Integer b = 5; Int c = b+5;Copy the code

2. Principle of automatic packing and unpacking

How to realize packing and unpacking is a little magical, it can make the basic type and packaging type quickly conversion. Let’s simplify the above example a bit:

Public class Test_6 {public static void main(String[] args) {// Pack Integer b = 5; Int c = b+5; }}Copy the code

Use javap -v test_6.class to view the bytecode information of the class file as shown in the following figure:

Integer.valueOf()
Integer.initValue()

This time we decompile back to the Java code and use jad test_6.class to generate the following decompile:

public class Test_6 { public static void main(String args[]) { Integer b = Integer.valueOf(5); int c = b.intValue() + 5; }}Copy the code

And this is pretty straightforward. The boxing and unboxing is not much of a problem, and is done by calling integer.valueof () (boxing) and integer.initValue () (unboxing). That is to say, automatic packing and unpacking mechanism is a syntax shorthand, for the convenience of programmers, eliminating the trouble of manual packing and unpacking, into automatic packing and unpacking

Check for packing or unpacking

In the following two examples, you may be confused as to whether boxing or unboxing was used.

 Integer x = 1;
 Integer y = 2;
 Integer z = x+y;
Copy the code

In fact, as long as you think carefully, you can know: this is the first unpacking and then packing. Because the Integer type is a reference type, it cannot be added, and must be unboxed into a primitive type to sum up, then boxed into an Integer. If you modify the above example to make Integer Short, the correct code looks like this:

 Short a = 5;
 Short b = 6;
 Short c = (short) (a+b);
Copy the code

3. Caching mechanism for wrapping classes

Let’s start with an example

public class MyTest {
    public static void main(String[] args) {
        Integer a = 5;
        Integer b = 5;
        
        Integer c = 129;
        Integer d = 129;

        System.out.println("a==b "+ (a == b));
        System.out.println("c==d "+ (c == d)); }}Copy the code

Running results:

A == b true C == d false

Well, why are a and B referring to the same object? Does the JVM also maintain a constant pool for wrapper types at class load time? If so, why are the addresses of variables C and D different? In fact, the JVM does not maintain a constant pool for wrapped classes. The variables a, B, c, and D are derived from boxing, which, as mentioned earlier, is actually the compiler automatically adding integer.valueof () methods. The secret is probably in this method, so let’s take a look at the source code for Integer.valueof (), as follows:

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
Copy the code

Low, integerCache. high]. If so, return the corresponding subscript element in the integerCache. cache array. Otherwise, a new object is created. Take a closer look at IntegerCache’s source code as follows:

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); // Get the upper limitif (integerCacheHighPropValue ! = null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; // Create array cache = new Integer[(high-low) + 1]; int j = low; // Populate the arrayfor(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) Assert IntegerCache. High >= 127; } privateIntegerCache() {}}Copy the code

Cache is a final Integer array containing elements in the range of [-128,127]. The array initialization code is wrapped in a static block, which means that the integerCache. cache array is initialized at class load time.

Looking back at the example above, the base type value used for variables A and B is 5, outside the range of [-128,127], so elements from the cache array are used, so the addresses of a and B are the same. C and D use a base type value of 129, which is out of the cache range, so each pair creates a pair on the heap.

Summary and supplement of wrapper class cache:

  • Wrapper classes are similar to String classes in that they are non-mutable, meaning that once created, they cannot be modified. Because of this feature, the object instances of both are safe in multithreading and do not have to worry about asynchronous modification, which provides a good guarantee that they can implement sharing by creating only one object share.
  • Instead of maintaining a constant pool by the JVM, the shared implementation of wrapped classes uses a caching mechanism (arrays) that is initialized at class load time and cannot be modified.
  • The array cache of the wrapper class is limited, caching only the basic type values in the range of one byte, that is, -128 to 127. (Character range 0 to 127)
  • Not all wrapper classes provide caching. Only Byte, Character, Short, and Integer provide caching. Long, Float, and Double do not.

Reference: http://www.cnblogs.com/jinggod/p/8425748.html

If there are any improper articles, please correct them. You can also pay attention to my wechat public number: Learn Java well and get high quality resources.