创建一个Sting

String有三种构造方法,分别为直接赋值、new String方法构造和字符串数组构造。

1
2
3
4
5
6
7
//方法1
String str1="hello";
//方法2
String str2=new String("hello");
//方法3
char[] arr={'h','e','l','l','o'};
String str3=new String(arr);

String是一种引用类型,内部并不存储字符串本身。

Sting的存储结构

观察下段代码,输出结果是什么?

1
2
3
4
5
6
7
String str1="hello";
String str11="hello";
String str2=new String("hello");
String str22=new String("hello");
String str3="world";
System.out.println(str1==str11); //true
System.out.println(str2==str22); //false

输出结果分别为true、false。

之所以出现这样的结果,是字符串的存储方式不同。字符串str1和str11这样的创建方式是将数据存放在字符串常量池,在常量池中,同一个数只有一份。字符串常量池在JVM中是StringTable类,实际是一个固定大小的HashTable。str2和str22是将数据存放在堆上,每new一次就会在堆上开辟一块空间。

下面这幅图是String内部存储结构的简单示意图。

Sting内部存储结构

总结:String类中两种对象实例化的区别:

  • 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
  • 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中,可以使用intern()方法手工入池
1
String str2=new String("hello").intern();

Sting的不可变性

字符串Sting是不可变的,所以每次字符串“+”加号拼接时都会产生一个新的对象,并不是在原对象的基础上拼接。

JDK中,String类由final修饰,value字符数组也由final修饰。

  • String类被final修饰,表明该类不能被继承。
  • value被修饰被final修饰,只是表明不能再引用其他数组,但是引用空间中的值仍能被修改。

所以,final并不是String对象不可变的原因。

如何理解 String 类型值的不可变?

https://www.zhihu.com/question/20618891/answer/114125846

String对象不可变,使用加号进行字符串拼接效率是很低的,每次都会创建一个新对象,中间还会有很多临时变量。可以使用StringBuffer和StingBuilder来进行字符串的修改。

StringBufferStringBuilder

String、StringBuffer、StringBuilder的区别:

  • String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
  • StringBuffer与StringBuilder大部分功能是相似的。StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
//字符串拼接
String str="panghu";
String str1 = str + "tx";
//字符串拼接
StringBuffer sb = new StringBuffer("panghu");
sb.append("tx");
//转化
//String---->StringBuffer
StringBuffer sb1=new StringBuffer();
System.out.println(sb1.append(str));
//StringBuffer--->String
String ss= sb.toString();
System.out.println(ss);