运行时常量池
class文件前4个字节固定为CAFEBABE
class文件中的ConstantPool中的数据有以下类型
运行时常量池
运行时常量池是每个类或每个接口class文件中常量池表的运行时表示
# A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file.
它包含几种常量,从编译时已知的数字字面到必须在运行时解决的方法和字段引用
# It contains several kinds of constants, ranging from numeric literals
# known at compile-time to method and field references that must be resolved at run-time.
运行时常量池的功能类似于传统编程语言的符号表,尽管它包含的数据范围比典型的符号表要广
# The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language,
# although it contains a wider range of data than a typical symbol table.
常量池(Constant Pool)就是一张表,虚拟机指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等信息
使用`javap -v Test.class`就可以看到
常量池是class文件中的,当该类被加载,常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
字符串常量池
public class Test {
public static void main(String[] args) {
// "=" 号的赋值方式并不会在堆上创建新的对象,而是在StringTable中搜索
// 如果StringTable中有这个字符则直接引用这个字符的地址
// 如果StringTable没有这个字符,则会在常量池中创建该字符,并引用地址
String s1 = "a";// 程序刚开始时是没有"a"这个对象的,执行到该行代码时才会创建
String s2 = "ab";
String s3 = "a" + "ab";// StringTable中两个都有
String s4 = "a" + "d";// 有一个
String s5 = "b" + "c";// 一个都没有
}
}
String对象中有一个不可变的值
# A String object has a constant (unchanging) value.
字符串字面量是String实例的引用
# String literals (§3.10.5) are references to instances of class String.
String类型的常量表达式总是被"内部化",以便共享唯一的实例,使用方法是String.intern
# Constant expressions of type String are always "interned" so as to share unique instances,using the method String.intern.
public native String intern();// (从string pool中找)
// A pool of strings, initially empty, is maintained privately by the class {@code String}.
// When the intern method is invoked,
// if the pool already contains a string equal to this {@code String} object as determined by
// the {@link #equals(Object)} method, then the string from the pool is returned.
// Otherwise, this {@code String} object is added to the pool and a reference to this {@code String} object is returned.
JAVA使用jni调用C++实现的StringTable的intern方法,StringTable的intern方法跟Java中的HashMap的实现是差不多的,只是不能自动扩容.
默认大小是1009.
String的StringPool是一个固定大小的Hashtable,默认值大小长度是1009.如果放进StringPool的String非常多,就会造成Hash冲突严重.
从而导致链表会很长,链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降(因为要一个一个找).
// jdk12
String s1 = "a";
String sq = new String("a");
System.out.println(sq == s1);// false
System.out.println(sq.intern() == s1);// true
// public String(String original) {
// this.value = original.value;
// this.coder = original.coder;
// this.hash = original.hash;
// }
// 程序中只有一个此对象
String s1 = "a";
String s2 = "a";// 并没有创建对象
String s3 = "a";// 并没有创建对象
System.out.println(s1 == s2);// true
System.out.println(s2 == s3);// true
public static void main(String[] args) {
// 创建了两个String对象(可通过debug方式查看String实例的数量变化)
String s2 = new String("a");
}
public static void main(String[] args) {
// 只创建了一个对象(可通过debug方式查看String实例的数量变化)
String s2 = "a";
}
public static void main(String[] args) {
String s = "a" + "b"; // 只创建了一个对象,编译器会直接将+号优化,ConstantPool中是"ab"
}
// It is advised to use equals(), not ==, to compare two strings.
// This is because == operator compares memory locations, while equals() method compares the content stored in two objects.
public static void main(String[] args){
// two objects will be created.
// One in the Heap Area and One in the String constant pool
// and the String object reference always points to heap area object.
// S1 refers to Object in the Heap Area
String s1 = new String("GFG"); // Line-1
// S2 refers to Object in SCP Area
String s2 = s1.intern(); // Line-2
// Comparing memory locations
// s1 is in Heap, s2 is in SCP
System.out.println(s1 == s2); // false
// Comparing only values
System.out.println(s1.equals(s2)); // true
// S3 refers to Object in the SCP Area.No need to create a new one object.
String s3 = "GFG"; // Line-3
System.out.println(s2 == s3); // true
}