1. new String("abc")究竟创建几个对象?
答: 一个或两个, 如果常量池中原来有"abc", 那么只创建一个对象; 如果常量池中原来没有"abc",则创建两个对象.
new String("abc")调用public String(String original)构造函数, 等于"abc"和new String()两个操作, 若字符串池中不存在"abc", 则会创建一个字符串常量"abc",并
将其添加到字符串池中; 若存在,则不创建, 然后new String()会在堆中创建一个新的对象.
而String s = new String("abc")可以分为两步:
第一步创建新对象new String("abc"); 第二步: 把新对象赋值给s.
String str="abc"; 这行代码创建了一个String对象。
String a="abc"; String b="abc"; 还是创建一个。
String a="ab"+"cd"; 创建三个对象.
在JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。由于String类是final的,它的值一经创建就不可改变,因此我们不用担心String对象共享而带来程序的混乱。字符串池由String类维护,我们可以调用intern()方法来访问字符串池。
我们再回头看看String a="abc";,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。因此,我们不难理解三个例子中头两个例子为什么是这个答案了。
只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,对此我们不再赘述。因此我们提倡大家用引号包含文本的方式来创建String对象以提高效率,实际上这也是我们在编程中常采用的。
2. 关于值传递与引用传递的疑问
public static void main(String[] args){
StringBuffer s1 = new StringBuffer("hello");
StringBuffer s2 = new StringBuffer("hello");
change(s1, s2);
System.out.println(s1);
System.out.println(s2);
}
publis static void change(StringBuffer s1, StringBuffer s2){
s1.append("world");
s2=s1;
}
输出: s1: helloworld, s2:hello
在调用s1.append("world");时会修改s1所指向的字符串的值, 因此会修改s1的值, 但在执行s2=s1时, 只是修改了s2的值,地址并没有修改, 因此对调用后原来的s2不产生影响.