Static constant pool and runtime constant pool

We parse the bytecode file with javap -v mytest.class

public class com.example.spring.jvmTest.MyTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC.ACC_SUPER
Constant pool# 1:= Methodref          #6.#23         // java/lang/Object."<init>":()V
   #2 = Methodref          #5.#24         // com/example/spring/jvmTest/MyTest.math:()V
   #3 = Class              #25            // com/example/spring/jvmTest/A
   #4 = Methodref          #3.#23         // com/example/spring/jvmTest/A."<init>":()V
   #5 = Class              #26            // com/example/spring/jvmTest/MyTest
   #6 = Class              #27            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/example/spring/jvmTest/MyTest;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;) V #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               math
  #19 = Utf8               a
  #20 = Utf8               Lcom/example/spring/jvmTest/A;
  #21 = Utf8               SourceFile
  #22 = Utf8               MyTest.java
  #23 = NameAndType        #7: #8          // "<init>":()V
  #24 = NameAndType        #18: #8         // math:()V
  #25 = Utf8               com/example/spring/jvmTest/A
  #26 = Utf8               com/example/spring/jvmTest/MyTest
  #27 = Utf8               java/lang/Object
{
  public com.example.spring.jvmTest.MyTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/example/spring/jvmTest/MyTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;) Vflags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #2                  // Method math:()V
         3: return
      LineNumberTable:
        line 6: 0
        line 7: 3
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  args   [Ljava/lang/String;

  public static void math();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=0
         0: new           #3                  // class com/example/spring/jvmTest/A
         3: dup
         4: invokespecial #4                  // Method com/example/spring/jvmTest/A."<init>":()V
         7: astore_0
         8: return
      LineNumberTable:
        line 10: 0
        line 11: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            8       1     0     a   Lcom/example/spring/jvmTest/A;
}
SourceFile: "MyTest.java"

Copy the code

Where Constant Pool is our static Constant pool, that is, the Constant pool inside the class file during load

While our code is running, we need to load the data from these static constant pools into memory. Once loaded into memory, it is called the runtime constant pool

String constant pool

Before JDK1.6, the string constant pool is in the method area (permanent generation). After 1.6, the string constant pool is separated from the method area and placed in the heap

Example 1 (JDK1.8) :

public static void main(String[] args) {
        String s1 = "hello";
        String s2 = new String("hello");
        String s3 = s2.internn();
        System.err.println(s1==s2);
        System.err.println(s2==s3);
        System.err.println(s1==s3);
        
        StringBuilder sb = new StringBuilder();
        sb.append("llo");
        String s4 = sb.toString().intern();
        System.err.println("llo".equals(s4)); } output:false
false
true
true
Copy the code
  • The String s1 = “hello” will go to the String constant pool and run equals() to find out if there is a “hello” object, and if there is, return the String directly. If not, a “Hello” object is created in the constant pool

  • String s2 = new String(“hello”)”, it has two steps,

  1. If there is no “hello” object in the string constant pool, then create a “Hello” object in the string constant pool.
  2. Go to the heap and create a “Hello” string object that returns a reference to the heap object
  • String s3 = s2.internn()It will go to the string constant pool and run equals() to see if there is an object for S2, and if so, return it directly. If not:
  1. In the case of JDK1.6, create a new object in the string constant pool, and create a pointer to the new object in the string constant pool, and return a reference to the new object
  2. If the value is greater than JDK1.6, create a pointer in the constant pool to the object in the heap and return a reference to the object in the heap
  • sb.append("llo")An “llo” object is created directly in the heap, not in the string constant pool, and a reference to the heap object is returned.

Example 2 (JDK1.8) :

public static void main(String[] args) {
            String s1 = new String("he") +new String("llo");
            Strings3 = s1.intern(); System.err.println(s1==s3); } JDK6 output:falseJDK6 + output:true
Copy the code
  1. New String(“he”) : = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he
  2. New String(“llo”) : = “llo” = “llo” = “llo” = “llo” = “llo” = “llo” = “llo”
  3. “He “+”llo”, the code becomes after compilationsb.append("he").append("llo")Since it is stringBuilder, only a “Hello” object will be generated in the heap
  4. S1.intern (), which returns an object in the heap via equals()

Example 3 (JDK1.8) :

public static void main(String[] args) {
        String ab = "ab";
        String k = "a"+"b"; System.err.println(ab==k); } output:true
Copy the code

The “+” sign between constants such as “a”+”b” is optimized to “ab” at compile time, and they both point to “ab” in the string constant pool, so it is true

Example 4 (JDK1.8) :

public static void main(String[] args) {
        String ab = "ab";
        String b = "b";
        String c = "a"+b; System.err.println(ab==c); } output:false
Copy the code

“A “+” b” because the reference type b cannot be determined during compilation, it will compile to StringBuider(“a”).append(b), which will generate an “ab” object in the heap. C refers to this object, so it will be false

Example 5 (JDK1.8) :

public static void main(String[] args) {
        String ab = "ab";
        final String b = "b";
        String c = "a"+b; System.err.println(ab==c); } output:true
Copy the code

The difference from the above example is that the final modifier can be determined during compilation, i.e. “a”+b is “a”+”b”, so true

Third, the basic type wrapper class object pool

Let’s look at some code:

public static void main(String[] args) {
        Integer a = 127;
        Integer b = 127;

        Integer a1 = 128;
        Integer b1 = 128;

        Integer a2 = new Integer(127);
        Integer b2 = new Integer(127); System.err.println(a==b); System.err.println(a1==b1); System.err.println(a2==b2); } output:true
false
false
Copy the code

So why?

  1. The Integer internally maintains a local cache ranging from -128 to 127,Integer a = 127During compilation it becomesInteger.valueOf(127), will go directly to the cache logic, the number in the cache, directly from the cache can be taken
  2. likenew Integer(127) This does not go through the cache logic, but directly to the heap to create the object

Note:

All of the eight large wrapper classes implement caching except Float and Double (because Float and Double are so broad that caching is not necessary)