String基本操作和字符串缓存池的理解
1、String字符串基本操作
String对象内容永远不变,也就是说String对象不变(引用变的),如果对String字符串进行 操作之后,形成一个新的字符串,且将其赋值给原字符串,原字符串的对象不变,而重新引用一个新对象(String str = “abc” ; str = str+”def”;在这种情况下, str就重新引用了”abcdef”这个对象,而原先创建的”abc”,”def”对象不变),String的比较是使用equals。也可是使用new String (str.getBtyes(“原编码”),”新编码格式”);来转化字符的编码格式。
问:String str = “abc” 与 String str = new String (“abc”) ;的区别?
答:上面两段代码的区别就在于我们在执行完这行代码之后究竟是创建了几个对象呢? 当然,这个两段代码相信大家对其并不陌生,答案也是总所周知的,String str = new String (“abc”) ;创建的对象是2个,String str = “abc”创建的对象为1 个。
我们可以把上面这行代码分成String str、=、"abc"和new String()四部分来看待。String str只是定义了一个名为str的String类型的变量,因此它并没有创建对象;=是对变量str进行初始化,将某个对象的引用(或者叫句柄)赋值给它,显然也没有创建对象;现在只剩下new String("abc")了。那么,new String("abc")为什么又能被看成"abc"和new String()呢?
我们来看一下被我们调用了的String的构造器:
public String(String original) { //other code ... } 大家都知道,我们常用的创建一个类的实例(对象)的方法有以下两种:
①、使用new创建对象。
②、调用Class类的newInstance方法,利用反射机制创建对象。
我们正是使用new调用了String类的上面那个构造器方法创建了一个对象,并将它的引用赋值给了str变量。同时我们注意到,被调用的构造器方法接受的参数也是一个String对象,这个对象正是"abc"。
由此我们又要引入另外一种创建String对象的方式的讨论——引号内包含文本。这种方式是String特有的,并且它与new 的方式有很大的区别。
String str = “abc” 毫无疑问,这行代码创建了一个String对象。
String a = “abc”; String b = “abc”; 那这里呢?答案还是一个;
String a = “ab” + “cd”; 在看这里? 答案是三个!
在Java虚拟机中存在着一个字符串缓存池,,其中保存着很多的String对象,并且可以被共享使用,也正因为如此大大的提高了效率。String类是flinal的,它的值一经创建就不可以改变,因此我们也就不用担心String对象共享而带来的程序混乱。字符串池由String类维护的,可以调用intern()方法来访问字符串池。
回过头再来看String a = “abc”,在行代码被执行时,虚拟机首先会在字符串池里面查找已经存在的值为”abc”的一个对象,根据String类的equals(Object obj)方法的返回值来判断,如果有,则不在创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。
使用引号包含文本的方式创建String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new 方式创建的对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。通常提倡大家使用引号包含文本的方式来创建String对象以提高效率。
说明:
栈(stack):保存基本类型(或者叫内置类型。如 char byte short int long float double boolean )和对象引用,数据可以共享,速度仅次于寄存器(register),快于堆(heap)。
堆(heap):用于存储对象。