Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared.
从这句话当中,我们可以知道String是一个不可变对象,对象的值不可以被改变。因为这一点,所以String是线程安全的。然后Stringbuffer是可变对象。
答:从String类的源码中,我们可以知道不可变对象是被final关键字修饰的类产生的对象,其成员变量也是被final修饰的,因此该类不能被修改也不能被继承。
不可变对象的好处主要体现在以下两方面:
1. 不可变对象是线程安全的,可用于多线程。在多线程通信中,某一个变量很可能被多个线程进行修改,因此是不安全的。而不可变对象不能被修改,安全;
2.不可变对象可以提高拷贝时的效率,不可变意味着拷贝时只需要拷贝地址,效率高。
public final class String
implements java.io.Serializable, Comparable, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
...........................................
}
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
/** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L;
}
而StringBuffer是继承了AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
}
从上面一段代码中再次可以看出,String和StringBuffer的区别,String是不可变对象,StringBuffer是不可变对象
从问题1中我们已经看到了其中一个主要的区别:String是不可变对象,StringBuffer是可变对象。这一点也导致了其他的很多的区别。
看下面两个例子字符串拼接:
String str = new String ("Stanford ");
str += "Lost!!";
StringBuffer str = new StringBuffer ("Stanford ");
str.append("Lost!!");
问:哪个效率高?
乍一眼看过去还真以为第一种方式高于第二种方式,其实不然。我们看两张程序的字节码。
0 new #7
3 dup
4 ldc #2
6 invokespecial #12
9 astore_1
10 new #8
13 dup
14 aload_1
15 invokestatic #23
18 invokespecial #13
21 ldc #1
23 invokevirtual #15
26 invokevirtual #22
29 astore_1
0 new #8
3 dup
4 ldc #2
6 invokespecial #13
9 astore_1
10 aload_1
11 ldc #1
13 invokevirtual #15
16 pop
在第一种方式中,由于String是不可变对象,所以在第10行的时候,它将string对象转换成了StringBuffer对象,再把字符拼接上去,在29行的时候重新转换成String对象,返回给用户。而在第二种方式中,StringBuffer是可变对象,直接拼接字符串并返回。从这一点很显然看出,在常见的字符串拼接问题上,String的效率比StringBuffer低。
再说StringBuilder,StringBuilder和StringBuffer一样都是可变对象,那有什么区别呢?我们稍微比较一下源码就可以看到StringBuffer中的大多数函数都带有关键字:synchronized和StringBuilder中没有。因此,StringBuilder在单线程中效率高于StringBuffer,而StringBuffer可以用于多线程。
String str = new String("abc");
String str = "abc";
这是我们常见的两种String对象的初始化方式,区别何在?首先我们来看一段代码。
String str1 = new String("abc"); //jvm 在堆上创建一个String对象
//jvm 在strings pool中找不到值为“abc”的字符串,因此
//在堆上创建一个String对象,并将该对象的引用加入至strings pool中
//此时堆上有两个String对象
Stirng str2 = "abc";
if(str1 == str2){
System.out.println("str1 == str2");
}else{
System.out.println("str1 != str2");
}
//打印结果是 str1 != str2,因为它们是堆上两个不同的对象
String str3 = "abc";
//此时,jvm发现String Pool中已有“abc”对象了,因为“abc”equals “abc”
//因此直接返回str2指向的对象给str3,也就是说str2和str3是指向同一个对象的引用
if(str2 == str3){
System.out.println("str2 == str3");
}else{
System.out.println("str2 != str3");
}
输出结果是什么?
再来看一段代码
String str1 = new String("abc"); //jvm 在堆上创建一个String对象
str1 = str1.intern();
//程序显式将str1放到String Pool中,intern运行过程是这样的:首先查看String Pool
//有没“abc”对象的引用,没有,则在堆中新建一个对象,然后将新对象的引用加入至
//String Pool中。执行完该语句后,str1原来指向的String对象已经成为垃圾对象了,随时会
//被GC收集。
//此时,jvm发现String Pool中已有“abc”对象了,因为“abc”equals “abc”
//因此直接返回str1指向的对象给str2,也就是说str2和str1引用着同一个对象,
//此时,堆上的有效对象只有一个。
Stirng str2 = "abc";
if(str1 == str2){
System.out.println("str1 == str2");
}else{
System.out.println("str1 != str2");
}
这个问题就涉及到Java的内存模型了,简单的说来区别在于:
第一种初始化方式会立即在对上创建一个String对象,然后将该对象的引用返回给用户。对于第二种,jvm首先会在String Pool判断是否存在该String对象。如果有,则返回已有的String对象,如果没有,则在heap中重新创建对象,将其引用返回给用户同时将该引用添加至String Pool中。而第一种方式是不会主动把对象添加至String Pool中的。因此第一段程序的输出结果是
str1 != str2
str1 == str2
那么第二段程序的输出结果呢?前面我们说到第一种方式是不会主动把对象添加至String Pool中的,但有个例外,手动调用intern()方法,会强制将该对象的引用加入到String Pool里面。因此第二段程序的结果是
str1 == str2
了解Java内存模型的都知道,在Java内存中有一块区域叫做方法区。方法区主要用于存储一些常量和静态变量。而String Pool和Const Pool的区别简单的说来,String Pool是Const Pool的一部分,Const Pool包括很多种常量,整型啊之类的,而String Pool只是用来专门存储String常量。
没有写完,持续更新。。。。