常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。
一、字符串的创建与初始化
在java中创建并初始化一个String对象,最常见的有两种方式
(1)String str 1= “hello”
JVM会先去字符串池中找有没有"hello",有的话就把str1指向常量池中的"hello",(也就是获取对hello的引用)没有就会先在创建一个字符串对象,并将其放入到字符串常量池,再让str1指向常量池中的"hello"。
“hello”放在常量区中,在编译时产生
String str 1= “hello”创建了几个对象?
创建时常量池中没有相同字符串则1个否则0个。
(2)String str1 = new String(“hello”)
new String(“hello”)此语句等价于“abc”和new String()两个操作。
如果在字符串常量池中不存在“hello”字符串,创建一个字符串常量“hello”,并将其添加到字符串常量池中;若存在,则不创建;
new String()会在堆里创建一个新的对象。
str1指向堆中创建的对象
String str1 = new String(“hello”)创建了几个对象?
创建时常量池中没有相同字符串则2个否则1
常见面试题:
(1)字符串的创建与存储问题
public static void main(String[] args)
<span style="white-space:pre"> </span> {
String s1 = "abc";//常量池中没有"abc",创建字符串常量"abc"biang放入常量池,让s1指向常量池中的"abc"
String s2 = "abc";//常量池中已经存在"abc",直接让s2指向常量池中的"abc",s1和s2指向常量池中的同一个对象
System.out.println(s1 == s2);//true “==“对你是否指向同一个对象,输出true
System.out.println(s1.equals(s2));//true equals方法对比的是指向的对象中的字符串内容是否相同
String s3 = new String("abc");//常量池中已经存在"abc",运行时在堆中生成一个字符串对象,s3指向堆中的对象
String s4 = new String("abc");//常量池中已经存在"abc",运行时在堆中新生成生成一个字符串对象,s4指向堆中的对象
System.out.println(s3 == s4);//false s3、s4指向对堆中不同的字符串对象
System.out.println(s3.equals(s4));//true 指向的对象中的字符串内容相同
System.out.println(s1 == s3);// false s1是指向字符串常量区 s3指向的是堆区
System.out.println(s1.equals(s3));//true 指向的对象中的字符串内容相同
}
内存空间如下:
(2)字符串的拼接
1)
String str1 = "aaa";
String str2 = "bbb";
String str3 = "aaabbb";
String str4 = "aaa" + "bbb";//两个字面字符串常量直接相加在编译时就str4确定为aaabbb,不会产生新的字符串对象
System.out.println(str3 == str4);//true str4与str3都是指向aaabbb
str4 = str1 + "bbb";//会产生新的字符串对象
System.out.println(str3 == str4);//false
str4 = str1 + str2;//会产生新的字符串对象
System.out.println(str3 == str4);//false
/*
* 使用“+”连接的两个字符串本身就是字面常量字符串时,如果池中存在这样连接后的字符串,
* 则是不会重新创建对象,而是直接引用池中的字符串对象;如果“+”连接的两字符串中只要
* 有一个不是字面常量串(即定义过的),是会产生新的字符串对象。
*/
2)若在定义字符串变量时加final关键字修饰并且在声明时就赋予初始值
final String str1 = "aaa";
final String str2 = "bbb";
String str3 = "aaabbb";
String str4 = str1 + str2;
System.out.println(str3 == str4);//true
解析:
因为str1与str2都定义成了常量,在编译时就能确定,编译时就会将常量替换,等同于
str4 = "aaa"+"bbb",因此不产生新对象
3)
final static String str1;
final static String str2; <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
static {
str1 ="aaa";
str2 ="bbb"; //此时str1与str2相当于变量,而不是常,因为块是在运行时才能确定,在编译时不能确定
}
public static void main(String[] args){
String str3 = str1 + str2;
String str4 ="aaabbb";
System.out.println(str3==str4); //输出为false
}