Java constant pool

  1. Relevant knowledge

  1. What is a constant

  The first kind of constant: is a value, and we call this value itself a constant. for example:

Integer constant: 1024
Real constant: 1.024
Character constants: 'g' 'c' 'w'
String constant: "gcw"
logical constant: true false

   For example, we can call the number 1024 a constant of type int.
  The second kind of constant: immutable variables, we also call constants. A variable modified by the keyword final cannot change its value. It may be a variable itself, but after being finalized, we can consider it a constant. for example:

final int i=1024;

   2. Constant pool

  There are two types of constant pools: static constant pools and runtime constant pools.
  (1) The static constant pool is also the constant pool in the Class bytecode file. Let's take a simple example, the following is the source file and Class file of a HelloWorld.
  Source File:

public class HelloWorld{
    public static void main(String args[]){
        System.out.println("hello world");
    }
}

   class file:

  We analyze the identifiers in the class file one by one.

  ①Magic number
  The magic number is the first four bytes in the class bytecode file: ca fe ba be (gargle). Its only role is to determine whether the file is acceptable to the JVM. Magic numbers are used for identification in many file storage standards.
  ②Version number
  The 5th and 6th bytes are the minor version number, and the 7th and 8th bytes are the major version number. The 7th and 8th bits here are 0034, that is: 0x0034. 0x0034 converted to decimal is 52. The version of Java starts from 45, but from 1.0 to 1.1 is 45.0 to 45.3, then 1.2 corresponds to 46, 1.3 corresponds to 47 ... 1.6 corresponds to 50, where 1.6.0_24 corresponds to 52, which is 0x0034;
  ③The entry of the constant pool
  Since the number of constants in the constant pool is not fixed, the entry of the constant pool needs to place a data of type u2, which represents the capacity count value of the constant pool. The constant pool capacity count value here starts from 1. As shown in the constant pool capacity: 0x001d (29). So there are 29 constants in total.
  ④Constant pool
  The constant pool mainly stores two types of constants: literals and symbolic references. Literal is a constant concept that is relatively close to the Java language level, which is the constant we mentioned. Symbolic references belong to the concept of compilation principles, including three types of constants: fully qualified names of classes and interfaces; names and descriptors of fields; names and descriptors of methods.

  (2) Runtime constant pool: The runtime constant pool is part of the method area. In addition to the description information of the class version, field, method, interface, etc. in the Class file, there is also a constant pool, which is used to store the literals and symbolic applications generated at compile time. This part of the content will enter the method after the class is loaded. stored in the runtime constant pool. The runtime constant pool has an even more important feature: dynamism. Java requires that the contents of the constant pool at compile time can enter the constant pool at runtime, and the constants generated at runtime can also be put into the pool. The most commonly used is the intern() method of the String class [when the intern() method is called, the compiler will add the string to the constant pool (stringTable maintenance) and return a reference to the constant. ].

  3. The benefits of the constant pool The
  constant pool is to avoid the frequent creation and destruction of objects and affect the system performance, which realizes the sharing of objects.
  For example, the string constant pool puts all string literals into a constant pool at compile time.
  (1) Save memory space: All the same string constants in the constant pool are merged, occupying only one space.
  (2) Save running time: == is faster than equals() when comparing strings. For two reference variables, only use == to determine whether the references are equal, and then you can determine whether the actual values ​​are equal.

  4. The difference between equals and ==
   There are two types of data types in Java: basic data types and reference data types.
  (1) There are 8 basic data types: byte short int long char float double boolean.
  For the comparison of basic data types, == is used to compare whether the two values ​​are equal.
  (2) Reference data types.
  Under normal circumstances, equals and == are the same, both of which are compared to see if the address values ​​of the two are the same. But there are also special cases. For example, we all know that all classes are inherited from the Object base class, and the equals method in Object is implemented using ==, that is, the address values ​​of the two are compared. However, subclasses of Object can override the equals method. For example, classes such as Date, String, and Integer override the equals() method to compare whether the values ​​are equal. For example, in the equals() source code of the String class, first compare whether they point to the same address, and if not, then compare whether the two are equal in value. At this time, the meanings expressed by equals and == are obviously different.  

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = count;
            if (n == anotherString.count) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = offset;
                int j = anotherString.offset;
                while (n-- != 0) {
                    if (v1[i++] != v2[j++])
                        return false;
                }
                return true;
            }
        }
        return false;
    }

   2.8 basic data types

  The 8 basic data types have their own wrapper classes, of which 6 wrapper classes (Byte, Short, Integer, Long, Character, Boolean) implement constant pool technology. For example, by looking at the source code of Integer, you will find that it has an internal static class IntegerCache, this internal static class is cached, and the range is [-128, 127], as long as the numbers within this range will be cached inside, so as to make The constant pool is managed. Let's look at an example:

package com.itszt.test5;
/**
 * Integer constant pool
 */
public class IntegerTest {
    public static void main(String[] args) {
        Integer i1=10;
        Integer i2=10;//Between [-128-127, store in the constant pool]
        System.out.println("i1 ==i2 ---> " + (i1==i2));

        Integer i3=1000;
        Integer i4=1000;//Beyond the range of the constant pool, create new objects each
        System.out.println("i3 ==i4 ---> " + (i3==i4));
    }
}

   The console prints the result:

i1 ==i2 ---> true
i3 ==i4 ---> false

   In the above code, the value of i1 is cached for the first time. When i2 is created, it actually points to the 10 that was cached for the first time, so i1 and i2 point to the same address; since i3 and i4 are both The range of the constant pool is exceeded, so two objects are recreated in the heap memory, and their addresses in the heap memory are not equal.

  If the new keyword is used, it means that a new memory hole is opened in the heap memory. Every time an object is new, a new space is opened up in the heap memory, so the address of each new object is different.

  Float and Double do not implement constant pools. The code demonstration is as follows:

        Float f1=10.0f;
        Float f2=10.0f;
        System.out.println("f1 =f2 ---> " + (f1==f2));

        Double d1=12.0;//The default is double type
        Double d2=12.0d;
        System.out.println("d1 =d2 ---> " + (d1==d2));    

   After the above code is executed in the main() main function, the console prints as follows:

f1 = f2 ---> false
d1 =d2 ---> false

   3. String class

  1. new String creates string objects on the heap.

   

  2. When the intern() method is called, the compiler adds the string to the constant pool (stringTable maintenance) and returns a reference to the constant.

  

  3. When a string is created by literal assignment (such as: String str=”twm”), it will first check whether the same string exists in the constant pool. If it exists, the reference in the stack will directly point to the string; If it does not exist, a string is generated in the constant pool, and the reference in the stack is pointed to the string.

  4. The "+" operation of the constant string will be directly synthesized into a string during the compilation phase. For example, string str=”JA”+”VA” will be directly merged into the statement String str=”JAVA” in the compilation stage, so it will go to the constant pool to find out whether there is “JAVA”, so as to create or refer to it.

  5. For final fields, constant replacement is performed directly at compile time (and for non-final fields, assignment processing is performed at runtime).
  final String str1=”ja”;
  final String str2=”va”;
  String str3=str1+str2;
  At compile time, it is directly replaced by String str3=”ja”+”va”, and then replaced by String str3=” JAVA".

  6. When a constant string and a variable are spliced ​​(eg: String str3=baseStr + "01";), ​​stringBuilder.append() will be called to create a new object on the heap memory.

  7. After JDK 1.7, the intern() method will still first check whether there is any existing in the constant pool. If it exists, it will return the reference in the constant pool, which is no different from before. The difference is that if it is in the constant pool If the corresponding string is not found, the string will not be copied to the constant pool, but only a reference to the original string will be generated in the constant pool. Simply put, what is put in the constant pool has changed: when it is not found in the constant pool, copy a copy and put it in the constant pool, and after 1.7, copy the address reference on the heap to the constant pool.

  

  4. Answers to frequently asked questions:

Q: The output of the following program:
String s1= “abc”;
String s2= “abc”;
System.out.println(s1==s2);
A: true, both point to objects in the constant pool.

Q: The output of the following program:
String s1=new String(“abc”);
String s2=new String(“abc”);
System.out.println(s1==s2);
A: false, the two references point to different objects in the heap.

Q: The output of the following program:
String s1 = “abc”;
String s2 = “a”;
String s3 = “bc”;
String s4 = s2 + s3;
System.out.println(s1 == s4);
A: false, because s2+s3 is actually done using StringBuilder.append,
        Different objects are generated.

Q: The output of the following program:
String s1 = “abc”;
final String s2 = “a”;
final String s3 = “bc”;
String s4 = s2 + s3;
System.out.println(s1 == s4);
A: true, because the final variable will be directly replaced with the corresponding value after compilation,
    So it is actually equal to s4 = "a" + "bc", and in this case,
    The compiler will merge directly into s4="abc", so in the end s1==s4.

Q: The output of the following program:
String s = new String(“abc”);
String s1 = “abc”;
String s2 = new String(“abc”);
System.out.println(s == s1.intern());
System.out.println(s == s2.intern());
System.out.println(s1 == s2.intern());
A:false,false,true。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324736745&siteId=291194637