字符串
知识点梳理
Java中提供了String、StringBuffer和StringBuilder三个类来封装字符串。同时也提供了一系列操作字符串的方法。这三个类容易被人们混淆,因此经常在笔试面试中拿来考察应试者,所以在此梳理一下这三个类。
String类是最基本的字符串类。String类的特点是一旦该类对象的被创建,对象中的字符序列就不能被修改,直到该对象被系统回收,所以String类是一个不可变的类。
与String类不同,StringBuffer类的对象代表一个一个字符序列可变的字符串。可以通过StringBuffer类提供的append、insert、reverse、setCharAt等方法修改该对象中字符序列的内容。一个StringBuffer类的对象可通过toString()方法生成一个String类的对象。
StringBuilder类是JDK 1.5之后新增的一个类。StringBuilder和StringBuffer很类似,不同之处在于StringBuffer的线程是安全的,而StringBuilder和StringBuffer很类似,不同之处在于StringBuffer类是线程安全的,而StringBuilder没有线程安全的机制,所以StringBuilder的性能要优于StringBuilder。
在理解字符串的时候有两个概念十分容易混淆,一个是在堆内存上创建的字符串对象,另一个是常量池中的字符串常量。对于初学者来说,这两个概念很容易造成困惑。
首先看在堆内存上创建一个字符串对象,例如:
String str=new String("abc");
其中变量str是一个引用类型的变量,它指向堆内存中的空间,里面存放了字符串"abc"。由于它是一个String类型的对象,则情况就不同了,例如:
Stirng str="abc";
字符串"abc"是一个字符串变量,它在编译时就被创建,并被保存在.class文件的常量池中。而在程序运行中,类会被加载到内存中,此时.class文件的常量池中的内容将在类加载器后进入方法区的运行的常量池中。所以此时引用变量str指向的并不是一般意义上的堆内存中的字符串对象,而是运行时常量池中的字符串常量。
与此同时,Java会确保每个字符串常量在常量池只有一个,不会产生多个副本。所以如果按照如下的方式来定义字符串
String str1=new String("abc");
String str2="abc";
String str3="abc";
System.out.println(str1==str2);
System.out.println(str2==str3);
str1str2的值为false,因为str1指向的是堆内存中的字符串对象,而str2指向的是常量池中的字符串常量。str2str3的值为true,因为它们都是指向常量池中的字符串常量,并且字符串"abc"在常量池中只有一个。
字符串的概念比较多,用法也十分灵活,因此历来都是考试重点
String类型的特性
如果执行了下面这两句程序:
String s="Hello";
s=s+"world!";
原始的String对象中的内容到底改变了没有?
分析:
String类型的对象一旦被创建,对象中的字符序列就不能被修改。也就是说,在执行完String s=“Hello”;这条语句后,变量s就指向了新的字符串常量"Hello",当字符串执行了一个新的字符串常量"Hello World!“,而原来的那个字符串常量任然在内存中,只是没有引用变量再指向它了。所以原始的String对象中的内容并没有发生任何变化,s指向了一个新的字符串变量"Hello world!”。
从上述分析可以知道,String是一个不可变类,当一个字符串需要经常被修改时,要尽量避免用String类修改字符串时会生成一些无用的中间对象(例如第一个字符串"Hello"),这样的无用对象在内存中不断积累增多而来不及被回收,久而久之会影响程序性能。
答案(answer)
原始的String对象中的内容并没有发生任何变化,仍然是字符串"Hello",s指向了一个新的字符串量"Hello world !"