标签:
在Java语言这种,字符串起着非常重要的作用,字符串的声明和初始化由以下两种情况:
1》对于字符串String s1 = new String("abc")语句与String s2 = new String("abc")语句,存在两种引用对象s1,s2,两个内容相同的字符串对象"abc",他们在内存中的地址是不同的。只要是用到new总会产生新的对象。
2》对于String s1 = "abc"和String s2 = "abc"语句,在JVM中存在一个字符串池,其中存有很多String对象,并且可以被共享使用,s1,s2引用同一个常连池中的对象,其中String采用Flyweight设计模式,当创建一个字符串常量时,例如String s="abc",会首先在字符串常量池中查找是否存在相同的字符串定义,其判断依据是String对象中的equals方法的返回值。若已经定义,则直接引用其定义,此时不需要创建新的对象;如果没有定义,则首先创建对象,然后把他加入到字符串池中,再将他的引用返回。由于字符串是不可变类,一旦创建好了就不可修改,因此字符串对象可以被共享而且不会引起程序的混乱。
具体而言:
String s = "abc"; //把abc放在常量区中,在编译时产生。
String s = "ab"+"c"; //把“ab”+“c”转换成字符串常量“abc”放在常量区中
String s =new String("anc"); //在运行时把abc放在堆中
例如:
String s1 = "abc"; //在常量区中存放了一个"abc"的字符串对象
String s2 = "abc";//s2引用常量区中的对象,因此不会创建新的对象。
String s3 = new String("abc");//在堆中创建新的对象
String s4 = new String("abc");//在堆中又创建一个新的对象
为了理解方便,可以吧String s = new String("abc")语句的执行分类两个过程;第一个过程就是新建对象的过程,即new String("abc");第二个过程就是赋值过程,即String s=。由于第二个过程仅仅创建了一个字符串类型的变量,将一个字符串对象的引用赋值给s,因此这个过程中不会创建新的对象。第一个过程new String("abc")调用String类中的构造方法:
public String(String origin) {
//body
}
在调用这个构造函数时,传入一个字符串常量,因此语句new String("abc")也就等价于"abc"和new String()两个操作了。若在字符串池中不存在abc,则会创建一个新的字符串常量“abc”,并将其添加到字符串池中;若存在则不创建,然后new String()会在堆中创建一个新的对象,所以s3和s4是指向不同的String对象,地址自然也就不同了。如图所示.
引申:对于string类型的变量s,赋值语句s=null与s=""是否相同?
对于赋值语句s=null,其中s是一个字符串类型的引用,它不指向任一个字符串。而赋值语句s=""中的s是一个字符串类型的引用,它指向另一个字符串(这个字符串的值为"",也就是空字符串),因此两则是不相同的。
常见的笔试题:
new String("abc")创建了几个对象?
answer:一个或者两个。如果常量池中原来有字符串"abc",那么只创建一个对象;如果常量池中没有字符串"abc",那么就创建两个对象(这两个对象分别位于字符串常量池和堆中)。
最后吐槽:为什么答,案二字会被审核不通过呢?想不明白
标签:
原文地址:http://my.oschina.net/ccqy66/blog/507100