java运行环境有一个字符串池。比如String str="abc"时,会首先查看字符串池中是否存在字符串"abc",如果存在则直接将"abc"赋给str,如果不存在则会先在字符串池中新建一个字符串"abc",然后再将其赋给str。如果执行代码
String str1="abc";
String str2="abc";
System.out.println(str1==str2);
则这段代码结果就会是true。执行str1时,会首先检查字符串池中是否存在"abc",如果有则直接赋给str1,如果没有则在字符串池中创建一个"abc"然后再赋给str1,当执行到str2时,检查字符串池已经存在了"abc",因此直接赋给str2,str1与str2指向同一个对象,所以结果为true。
而执行String str=new String("abc")时,不管字符串池中有没有"abc"都会在堆中新建一个字符串对象然后将其赋给str引用。所以执行如下代码
String str1=new String("abc");
String str2=new String("abc");
System.out.println(str1==str2);
结果就会为false,因为str1与str2指向的分别是两个不同的对象。
String str1="abc";
String str2="def";
String str3=str1+str2;
System.out.println(str3=="abcdef");
//结果肯定是为false
因为str3指向堆中的"abcdef"对象,而"abcdef"是字符串池中的对象,因为结果为false。JVM对String str="abc"对象放在常量池中是在编译时做的,而String str3=str1+str2是在运行时刻才能知道的。new对象也是在运行时才做的。而这段代码总共创建了5个对象,字符串池中两个、堆中三个。+运算符会在堆中建立来两个String对象,也就是说从字符串池中复制这两个值,然后在堆中创建两个对象,然后再建立对象str3,然后将"abcdef"的堆地址赋给str3。
而如果
String str="abc"+"def"; //直接将"abcdef"放入字符串池中
System.out.println(str=="abcdef");
//结果为true
String str1="abc";
String str2=str1+"def"; //str1是在堆中创建的对象
System.out.println(str2=="abcdef");
//结果为false
由于字符串对象的大量使用(它是一个对象,一般而言对象总是在堆中分配内存),Java中为了节省内存空间和运行时间(如比较字符串时,==比equals()快),在编译阶段就把所有的字符串文字放到一个字符串池中,而运行时字符串池成为常量池的一部分。字符串池的好处,就是该池中所有相同的字符串常量被合并,只占用一个空间。
我们知道,对两个引用变量,使用==判断它们的值(引用)是否相等,即指向同一个对象:
String s1 = "abc" ;
String s2 = "abc" ;
if( s1 == s2 ) System.out.println("s1,s2 refer to the same object");
else System.out.println("trouble");
这里的输出显示,两个字符串文字保存为一个对象。就是说,上面的代码只在字符串中创建了一个String对象。
现在看String s = new String("abc");语句,这里"abc"本身就是pool中的一个对象,而在运行时执行new String()时,将字符串池中的对象复制一份放到堆中,并且把堆中的这个对象的引用交给s持有。ok,这条语句就创建了2个String对象。
String s1 = new String("abc") ;
String s2 = new String("abc") ;
if( s1 == s2 ){ //不会执行的语句}
这时用==判断就可知,虽然两个对象的"内容"相同(equals()判断),但两个引用变量所持有的引用不同,上面的代码创建了几个String 对象? (3个,字符串池中1个,堆中2个。)
创建字符串有两种方式:两种内存区域(字符串池,堆)
1," " 引号创建的字符串在字符串池中
2,new,new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则导致浪费池的空间)
另外,对字符串进行赋值时,如果右操作数含有一个或一个以上的字符串引用时,则在堆中再建立一个字符串对象,返回引用;如String str2=str1+ "abc";
比较两个已经存在于字符串池中字符串对象可以用"=="进行,拥有比equals操作符更快的速度。
分享到:
相关推荐
java 字符串转16进制 16进制转字符串 将两个ASCII字符合成一个字节; java 字符串转16进制 16进制转字符串 将两个ASCII字符合成一个字节; java 字符串转16进制 16进制转字符串 将两个ASCII字符合成一个字节; java ...
java字符串处理取出括号内的字符串 都是我自己试过可以用的j
java 字符串 详细实例代码 字符串检索 可改变字符串 字符串生成器 日期和时间字符串格式化
java压缩字符串
JAVA的字符串拼接与性能 概述:本文主要研究的是JAVA的字符串拼接的性能,原文中的测试代码在功能上并不等价,导致concat的测试意义不大。不过原作者在评论栏给了新的concat结果,如果有兴趣的同学建议自己修改代码...
java 字符串的加密 java 字符串的加密 java 字符串的加密
89.java字符串方法.zip89.java字符串方法.zip89.java字符串方法.zip89.java字符串方法.zip89.java字符串方法.zip89.java字符串方法.zip89.java字符串方法.zip89.java字符串方法.zip89.java字符串方法.zip89.java字符...
有关java里的一些字符串的总结,适合java初学者学习。
java 分解字符串 java 分解字符串 java 分解字符串
java字符串的各种编码转换. java字符串的各种编码转换
JAVA 字符串 操作
96.java字符串反转案例.zip96.java字符串反转案例.zip96.java字符串反转案例.zip96.java字符串反转案例.zip96.java字符串反转案例.zip96.java字符串反转案例.zip96.java字符串反转案例.zip96.java字符串反转案例.zip...
29.java字符串+操作.zip29.java字符串+操作.zip29.java字符串+操作.zip29.java字符串+操作.zip29.java字符串+操作.zip29.java字符串+操作.zip29.java字符串+操作.zip29.java字符串+操作.zip29.java字符串+操作.zip29...
java中求字符串表达式的值看起来很伤脑筋,但如果你用BeanShell,一切都变得很简单。
Java字符串长度不够前面或后面补0
JAVA日期与字符串的转换 1) 将一个Date类型的变量转换为字符串 2) 将一个字符串转换Date类型的变量
JAVA字符串处理函数列表一览 JAVA字符串相关
Java分割字符串
java 字符串截取工具类java 字符串截取工具类
JAVA字符串操作类CTool.java字符转换类,此类中收集Java编程中WEB开发常用到的一些工具。为避免生成此类的实例,构造方法被申明为private类型的。封装的功能:字符串从GBK编码转换为Unicode编码、对字符串进行md5...