目录
String 、StringBuilder、StringBuffer对比
创建String实例的方式:
// 在方法区的常量池生成一个字符串abc,如果
String str1 = "abc";
// str2 和str1引用的是同一个字符串,也就是说在常量池中只有一个abc
String str2 = "abc";
// 本质上 this.value = new char[0];
String str3 = new String();
// 本质上 this.value = original.value;
String str4 = new String(String original);
// 本质上 this.value = Arrays.copyOf(value,value.length)
String str5 = new String(char[] a);
/
String str6 = new String(char[] a,int startIndex,int count)
两种创建String对象方法的原理对比:
例题1:
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
String str4 = new String("abc");
System.out.println(str1==str2); // true
System.out.println(str1==str3); // false
System.out.println(str1==str4); // false
System.out.println(str3==str4); // false
原理如下:
例题2:
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Person p1 = new Person("Tom", 12);
Person p2 = new Person("Tom", 13);
// true
System.out.println(p1.name == p2.name);
原理:
例题3:
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
String name1 = new String("Tom");
String name2 = new String("Tom");
Person p1 = new Person(name1, 12);
Person p2 = new Person(name2, 13);
// false
System.out.println(p1.name == p2.name);
面试题:
String s = new String("abc")
以上方法在内存中创建了几个对象:
两个;一个是对空间中new结构,另一个是char[ ]对应的常量池中的数据:"abc"。
例题4:
String s1 = "Hello";
String s2 = "World";
String s3 = "HelloWorld";
String s4 = "Hello" + "World";
String s5 = s1 + "World";
String s6 = "Hello" + s2;
String s7 = s1 + s2;
System.out.println(s3==s4); // true
System.out.println(s3==s5); // false
System.out.println(s3==s6); // false
System.out.println(s3==s7); // false
System.out.println(s5==s6); // false
System.out.println(s5==s7); // false
System.out.println(s6==s7); // false
String s8 = s5.intern();
System.out.println(s3==s8); // true
// s9是常量,常量与常量的运算在常量池中
final String s9 = "Hello";
String s10 = s9 + s2;
System.out.println(s10==s3); // true
原理:
结论:
- 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量
- 只要其中有一个是变量,结果就在对重
- 如果拼接的结果调用intern方法,返回值就在常量池中
例题5
public class test03 {
String str = new String("good");
char[] ch = {'t', 'e', 's', 't'};
public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'b';
}
public static void main(String[] args) {
test03 str = new test03();
str.change(str.str, str.ch);
System.out.println(str.str); // good
System.out.println(str.ch); // best
}
}
String 、StringBuilder、StringBuffer对比
1、String :不可变的字符序列,底层使用char[ ]存储
2、StringBuffer:可变的字符序列,线程安全的--效率低;底层使用char[ ]存储
3、StringBuilder:可变的字符序列,jdk5.0新增的,线程不安全的,效率高,底层使用char[ ]存储
源码分析:
String str = new String(); // char[ ] value = new char[0];
String str1 = new String("abc"); // char[ ] value = new char[ ]{'a','b','c'}
StringBuffer sb1 = new StringBuffer(); // char[ ] value = new char[16]; 底层创建了一个长度为16的数组
System.out.println(sb1.length()); // 输出结果为0,因为底层返回的是另一个变量count,而不是直接返回数组value的长度
sb1.append('a'); // value[0] = 'a';
sb1.append('b'); // value[1] = 'b'
StringBuffer sb2 = new StringBuffer("abc"); char[ ] value = new char["abc".length() + 16]
问题1:扩容问题:如果要添加的数据底层数据盛不下,那就需要扩容底层数组,默认情况下,扩容为原来容量的2倍 + 2,同时将原有数据的元素复制到新的数组中