先说说String,StringBuffer和StringBuilder的区别吧
String是字符串常量,用final修饰,StringBuffer是字符串变量,它是线程安全的,StringBuilder也是字符串变量,但是他是线程不安全的.
String和StringBuffer的区别在于性能,String是不可变的对象,每次对String进行操作实际上是生成了一个新String的对象,而原来的就会成为垃圾,所以我们在代码中尽量不对String做大量的操作,但是有一点需要注意的是,JVM对字符串拼接做了一定的优化,比如:String s = "ab" +"dc";会在编译的时候直接生成String = "abdc";此时就不存在拼接过程.
StringBuffer和StringBuilder相比较StringBuffer是线程安全的可变字符串,其内部实现是可变的数组,StringBuilder是java5.0新增的一个类,功能和StringBuilder类似,但是线程非安全,因此在没有多线程问题的前提下,StringBuilder会获得更好的性能.
然后说说String的常见面试题:
1.判断定义为String类型的s1和s2是否相等
* String s1 = "abc";
* String s2 = "abc";
* System.out.println(s1 == s2); //true
* System.out.println(s1.equals(s2)); //true
我先直接上一张内存图然后在解释一下:
简单的说创建s1的时候会在常量池中创建一个"abc",这个"abc"有一个地址值,然后s1把引用指向"abc"的地址值;创建s2的时候会在常量池中去检查是否有"abc",如果有就直接把引用指向"abc"的地址值,所以s1和s2的地址值相等.
2.下面这句话在内存中创建了几个对象?
* String s1 = new String("abc");
我们先来看一下String类的构造方法:
String(String original)
初始化一个新创建的
String
对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。
然后在画一下内存图:
综合构造方法和内存图简单的解释一下:内存的顺序是这样的,先是方法进栈,创建一个s1对象,然后在常量池创建一个"abc",然后在堆内存中复制一个"abc"的副本,但有自己的地址值0x0011,最后再把s1的引用指向0x0011.
3.判断定义为String类型的s1和s2是否相等
* String s1 = new String("abc");
* String s2 = "abc";
* System.out.println(s1 == s2); //false
* System.out.println(s1.equals(s2)); //true
这个题和上面的题很像,创建的两个对象一个引用指向的是堆内存,另一个地址是指向常量池.
4.判断定义为String类型的s1和s2是否相等
* String s1 = "a" + "b" + "c";
* String s2 = "abc";
* System.out.println(s1 == s2); //true
* System.out.println(s1.equals(s2)); //true
这个题是考的jvm的对String类的常量优化机制, String s1 = "a" + "b" + "c";代码在编译的时候就会生成String s1 = "abc";在创建s2的时候常量池中已经有"abc"了,会直接把引用指向"abc",所以s1和s2的地址值是一样的.
5.判断定义为String类型的s1和s2是否相等
* String s1 = "ab";
* String s2 = "abc";
* String s3 = s1 + "c";
* System.out.println(s3 == s2); //false
* System.out.println(s3.equals(s2)); //true
String类的api这样说的:
Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过
StringBuilder
(或
StringBuffer
)类及其
append
方法实现的。字符串转换是通过
toString
方法实现的,该方法由
Object
类定义,并可被 Java 中的所有类继承。
然后我们再来看一张内存图:
简单的解释一下内存中的顺序:
①主方法进栈,创建s1对象,然后在常量池中创建"ab",s1把引用指向"ab"的地址值,
②创建s2对象,然后在常量池中创建"abc",s2把引用指向"abc"的地址值,
③创建s3,然后在堆内存中创建StringBuffer或者StringBuilder的对象,利用append()方法,把"abc"赋值给该对象,再利用toString()方法在堆内存中创建出String对象,值为"abc",地址值为"0x0022,最后把s3的引用指向0x0022
所以,s2和s3地址值不相等.