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,
- If there is no “hello” object in the string constant pool, then create a “Hello” object in the string constant pool.
- 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:
- 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
- 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
- New String(“he”) : = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he” = “he
- New String(“llo”) : = “llo” = “llo” = “llo” = “llo” = “llo” = “llo” = “llo”
- “He “+”llo”, the code becomes after compilation
sb.append("he").append("llo")
Since it is stringBuilder, only a “Hello” object will be generated in the heap - 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?
- The Integer internally maintains a local cache ranging from -128 to 127,
Integer a = 127
During compilation it becomesInteger.valueOf(127)
, will go directly to the cache logic, the number in the cache, directly from the cache can be taken - like
new 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)