Java| String s=new String("abc")和Stirng s = "abc"的区别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011479200/article/details/83152328


本文希望能弄懂的问题: String s=new String(“abc”)和String s = "abc"的区别?

思考: 在Java中,我们是如何创建一个类的实例的?
在我们常用的创建一个类的实例(对象)的方法有以下两种:
一、使用new创建对象。
二、调用Class类的newInstance方法,利用反射机制创建对象。


一.使用""创建String对象的规则(String s1 = “yveshe”)

先来一到面试题,看看输出结果是什么:

String s1 = "yveshe";
String s2 = "yveshe";

System.out.println(s1 == s2); 
System.out.println(s1 == "yveshe"); 
System.out.println("Hello Yves" == "Hello Yves"); 

输出结果如下:

true
true
true

通过前提介绍我们知道创建已给类的实例(对象)有两种方法:通过new关键字创建对象,或者使用反射机制创建类的实例对象.显然在String s1 = "yveshe";产生String类的实例不包括在其中,这就是一种特的产生String类实例对象的方式.那么它的规则到底是怎样的呢?

String s1 = "yveshe";,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"yveshe"的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,该放在了字符串池中,再将它的引用返回。

在执行String s2 = "yveshe";其实字符串"yveshe"已经在常量池中存在,所以并不会创建新的对象而是将原来字面量"yveshe"的引用地址返回了.

总结:

使用""创建的String对象的方式,首先会在常量池中查找是否已经存在字符串字面量,存在返回已经存在字符串的引用,否则先创建这个对象,该对象存放在String Pool中,然后将他的引用返回.


二使用new关键字创建String对象的规则(String s= new String(“YvesHe”))

我们先来看一到面试题,如下代码创建了几个对象?

String s= new String("YvesHe");

答案是创建了2个对象,一个是字面量"YvesHe"创建的String对象,在String Pool中,一个是new操作产生的String对象,存放在Java Heap中.
(这里假定了StringPool中在代码运行之前不存在"YvesHe",否则则只会创建一个由于new操作产生的String对象,原理分析可以看第一大点)

扫描二维码关注公众号,回复: 3643128 查看本文章

分析如下:
我们可以把上面这行代码分成String s、=、"YvesHe"和new String()四部分来看待。
String s只是定义了一个名为s的String类型的变量,因此它并没有创建对象;
=是对变量s进行初始化,将某个对象的引用(或者叫句柄)赋值给它,显然也没有创建对象;
最后的new String(“abc”)又能被看成"abc"和new String();

不理解的new String(“abc”)又能被看成"abc"和new String();需要思考下如下代码:

String s= new String("YvesHe");

String tmp = "YvesHe";
String s= new String(tmp);

总结:
new 关键字一定会创建一个新的对象,存放在Java Heap中.


三.使用+操作符号创建的String对象

示例一:

String s1 = "yves" + "he";
System.out.println(s1 == "yveshe"); 

输出结果:

true

反编译代码如下:

String s1 = "yveshe";
System.out.println(s1 == "yveshe");

分析:

String s1 = "yves" + "he";在编译期常量折叠成String s1 = "yveshe";所以输出结果为true.

示例二:

String s1 = "yves";
String s2 = s1 + "he";
System.out.println(s2 == "yveshe");

输出结果:

false

反编译代码如下:

String s1 = "yves";
String s2 = (new StringBuilder(String.valueOf(s1))).append("he").toString();
System.out.println(s2 == "yveshe");

从反编译的代码结果,我们可以知道s2的String实例对象的产生形式是使用的StringBuilder的toString方法底层是使用String的public String(char value[], int offset, int count)构造方法,这里产生的对象并不会放在String Pool中.所以上面输出结果为false.如果打印语句修改为System.out.println(s2.intern() == "yveshe");,则会打印true.


四.String s = new String("YvesHe").intern();中intern方法到底作用何在?

String s = new String("YvesHe").intern();
System.out.println(s == "YvesHe");

输入结果:

true

分析:

1.首先创建一个字面量为"YvesHe"的String对象,存放在String Pool中. (假定运行该代码之前String Pool中无字面量"YvesHe"存在)
2.然后通过String的构造方法new String(String original)来产生一个新的String对象,存放在JavaHeap中,构造参数为字面量"YvesHe"在String Pool的引用
3.通过在JavaHeap上创建的String实例调用它的intern方法来获得String Pool中"YvesHe"的引用
等价如下:

String stringPoolRef = "YvesHe";
String javaHeapRef = new String(stringPoolRef);
String stringPoolRefSame = javaHeapRef.intern();
System.out.println(stringPoolRef == stringPoolRefSame);

到此,我们都没有发现intern的方法的正真作用,反倒是觉得很多余,因为无论是我们通过 String s = “YvesHe”; 还是String s = new (“YvesHe”);其实本质都会在String pool中生成了一个字面量为"YvesHe"的对象,接下来我们看下以下代码的运行结果

String s1 = "yves";
String s2 = "he";
String s3 = s1 + s2;

System.out.println(s3 == "yveshe");

输出结果:

false

我们先反编译一下以上代码:

String s1 = "yves";
String s2 = "he";
String s3 = (new StringBuilder(String.valueOf(s1))).append(s2).toString();
System.out.println(s3 == "yveshe");

从反编译的代码结果,我们可以知道s3的String实例对象的产生形式是使用的StringBuilder的toString方法底层是使用String的public String(char value[], int offset, int count)构造方法,这里产生的对象并不会放在String Pool中.所以上面输出结果为false.如果打印语句修改为System.out.println(s3.intern() == "yveshe");,则会打印true.

总结:

intern()方法有两个作用,第一个是将字符串字面量放入常量池(如果池没有的话),第二个是返回这个常量的引用。

参考:
http://rednaxelafx.iteye.com/blog/774673
http://www.hollischuang.com/archives/2517
https://www.cnblogs.com/ydpvictor/archive/2012/09/09/2677260.html

猜你喜欢

转载自blog.csdn.net/u011479200/article/details/83152328