创建字符串对象有两种方式
一种是通过初始化的方式创建
String str="Hello";
另一种是使用new关键字创建
String str = new String("Hello");
Java为了避免产生大量的字符串对象,设计了一个字符串池(String Pool),通过初始化方式创建的字符串对象都会存在于字符串池中,且字符串池中的字符串不会重复,以便可以被共享使用,提高存储效率。
其工作原理是:
当使用初始化的方式创建对象时,JVM会首先检查字符串池中是否存在值相等的字符串,如果存在,则不进行创建,而是直接返回字符串池中该字符串的引用地址。如果不存在,则创建该对象,并放入字符串池中,返回新创建的字符串的引用地址。
当使用new关键字创建对象时,JVM仍然首先检查字符串池中是否存在要创建的字符串,如果不存在,则在字符串池中创建一个字符串对象,然后在堆内存中继续创建一个字符串对象,返回该对象的引用地址。如果存在,则只在堆内存中创建一个字符串对象,返回该对象的引用地址。
使用new关键字创建字符串对象,实际上调用了String类的构造函数,构造函数的源码如下:
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
从上述代码可以看出,构造函数需要传入一个String对象,然后将该对象的值作为当前对象的值。因此,执行代码String str = new String(“Hello”);时,如果字符串池中不存在字符串“Hello”,则会创建两个对象,因为字符串“Hello”本身就是一个对象,通过关键字new又创建了一个对象。
详解+实例!
String str1 = new String("Hello");①
String str2 = new String("Hello");②
String str3 = "Hello"; ③
String str4 = "Hello"; ④
System.out.println(str1 == str2); //false
System.out.println(str3 == str4); //true
System.out.println(str2 == str3); //false
System.out.println(str1.equals(str2)); //true
System.out.println(str3.equals(str4)); //true
String str5=str4;⑤
System.out.println(str4 == str5); //true
str5="World";⑥
System.out.println(str4);//Hello
System.out.println(str5);//World
当代码运行到第①行后,JVM首先会查找字符串池中是否存在值为“Hello”的对象,发现不存在,则在字符串池中创建一个“Hello”对象,在堆内存中也创建一个“Hello”对象,并将堆内存中的“Hello”对象的引用(内存地址)赋给变量str1,此时字符串在内存中的存储示意图如下:
String str1 = new String("Hello");
字符串在内存中的存储示意图
当代码运行到第②行后,JVM首先会查找字符串池中是否存在值为“Hello”的对象,发现存在,则只在堆内存中创建一个值为“Hello”的对象,此时字符串在内存中的存储示意图如下:
String str2 = new String("Hello");
字符串在内存中的存储示意图
当代码运行到第③行后,JVM首先会查找字符串池中是否存在值为“Hello”的对象,发现存在该对象,则将该对象的引用赋给变量str3,此时字符串在内存中的存储示意图如下:
String str3 = "Hello";
字符串在内存中的存储示意图
当代码运行到第④行后,同理,会将“Hello”对象的引用赋给变量str4。
String str4 = "Hello";
当代码运行到第⑤行后,会将str4的引用赋给str5,
String str5=str4;
字符串在内存中的存储示意图
当代码运行到第⑥行后,JVM会首先查找字符串池中是否存在值为“World”的对象,发现不存在,则创建一个“World”对象,并将该对象的引用赋给变量str5,此时字符串在内存中的存储示意图如下:
str5="World";
字符串在内存中的存储示意图
到此,str5的引用是对象“World”;str4和str3的引用是同一个对象“Hello”;str2和str1的引用是不同的对象“Hello”。