String str=new String("abc"); 紧接着这段代码以后的每每是这个问题,那就是这行代码究竟建立了几个String对象呢?编程
相信你们对这道题并不陌生,由于有new,因此堆中必然有一个对象。另外,若是常量池中已有"abc",则不建立,没有,则在常量池中建立。因此这句代码,究竟在内存中建立一个仍是两个对象,视状况而定。优化
接下来咱们就从这道题展开,一块儿回顾一下与建立String对象相关的一些JAVA知识。 spa
咱们能够把上面这行代码分红String str、=、"abc"和new String()四部分来看待。String str只是定义了一个名为str的String类型的变量,所以它并无建立对象;=是对变量str进行初始化,将某个对象的引用(或者叫句柄)赋值给 它,显然也没有建立对象;如今只剩下new String("abc")了。那么,new String("abc")为何又能被当作"abc"和new String()呢?code
咱们来看一下被咱们调用了的String的构造器: 对象
public String(String original) { //other code ... } 你们都知道,咱们经常使用的建立一个类的实例(对象)的方法有如下两种:内存
1、使用new建立对象。 字符串
2、调用Class类的newInstance方法,利用反射机制建立对象。虚拟机
咱们正是使用new调用了String类的上 面那个构造器方法建立了一个对象,并将它的引用赋值给了str变量。同时咱们注意到,被调用的构造器方法接受的参数也是一个String对象,这个对象正 是"abc"。由此咱们又要引入另一种建立String对象的方式的讨论——引号内包含文本。编译
这种方式是String特有的,而且它与new的方式存在很大区别。 效率
String str = "abc";
毫无疑问,这行代码建立了一个String对象。
String a = "abc"; String b="abc"; 那这里呢?
答案仍是一个。
String a="ab"+"cd"; 再看看这里呢?
答案是1个。这个只是建立了一个对象,在编译时期已经进行优化了。说到这里,咱们就须要引入对字符串池相关知识的回顾了。
在JAVA虚拟机(JVM)中存在着一个字符 串池,其中保存着不少String对象,而且能够被共享使用,所以它提升了效率。因为String类是final的,它的值一经建立就不可改变,所以咱们 不用担忧String对象共享而带来程序的混乱。字符串池由String类维护,咱们能够调用intern()方法来访问字符串池。
咱们再回头看看String a="abc";,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的这么一个对象,它的判断依据是String 类equals(Object obj)方法的返回值。若是有,则再也不建立新的对象,直接返回已存在对象的引用;若是没有,则先建立这个对象,而后把它加入到字符串池中,再将它的引用返 回。所以,咱们不难理解前面三个例子中头两个例子为何是这个答案了。
只有使用引号包含文本的方式建立的 String对象之间使用“+”链接产生的新对象才会被加入字符串池中。对于全部包含new方式新建对象(包括null)的“+”链接表达式,它所产生的 新对象都不会被加入字符串池中,对此咱们再也不赘述。所以咱们提倡你们用引号包含文本的方式来建立String对象以提升效率,实际上这也是咱们在编程中常 采用的。
栈(stack):主要保存基本类型(或者叫内置类型)(char、byte、short、int、long、float、double、boolean)和对象的引用,数据能够共享,速度仅次于寄存器(register),快于堆。
堆(heap):用于存储对象