创建对象的思考
下面两种创建String对象的方式相同吗?
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s3 == s4); // false
}
上述程序创建方式类似,为什么s1和s2引用的是同一个对象,而s3和s4不是呢?
在Java程序中,类似于:1, 2, 3,3.14,“hello”等字面类型的常量经常频繁使用,为了使程序的运行速度更快、
更节省内存,Java为8种基本数据类型和String类都提供了常量池
为了节省存储空间以及程序的运行效率,Java中引入了:
- Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息
- 运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池,运行时常
量池每个类都有一份 - 字符串常量池
字符串常量池(StringTable)
字符串常量池在JVM中是StringTable类,实际是一个固定大小的HashTable(一种高效用来进行查找的数据结构,后序给大家详细介绍),不同JDK版本下字符串常量池的位置以及默认大小是不同的:
再谈String对象创建
由于不同JDK版本对字符串常量池的处理方式不同,此处在Java8 HotSpot上分析
- 直接使用字符串常量进行赋值
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true
}
说明
2. 在字节码文件加载时,hello和world常量已经创建好了,并保存在字符串常量池中
3. 当使用String s1=“hello”;创建对象时,现在字符串常量池中找,找到了,直接将该字符引用赋给s1
intern方法
intern 是一个native方法(Native方法指:底层使用C++实现的,看不到其实现的源代码),该方法的作用是手动将创建的String对象添加到常量池中。