字符串String与字符串池StringPool

 新建String对象到底生成几个对象呢?下面将对其进行详细介绍

 

package com.jadyer.detail;  
  
/** 
 * String对象与StringPool之间的是是非非 
 * @author 玄玉 
 * 
 */  
public class StringPoolTest {  
    public static void main(String[] args) {  
          
        //【执行完该行代码,会在内存中生成两个对象,二者的内容都是abc】  
        //第一个对象在StringPool中,第二个对象在Java堆内存中  
        //注意:这里的s不是对象,s是对象的地址,叫做引用,它指向的是堆内存中的对象  
        //而StringPool是java.lang.String类所特有的,由于经常要用到String类的对象  
        //所以JVM内部为了能够重复使用String对象,便专门使用一片内存空间缓冲已存在的String对象  
        //★补充★:字符串常量池的作用域是整个虚拟机中,某种意义上讲是一个工程中  
        //在生成字符串对象的时候,String的执行流程如下:  
        //它首先到StringPool中查找,是否存在内容为abc的对象  
        //如果此时StringPool中已经存在abc对象,那么它就不会在StringPool中创建abc对象了  
        //但由于该行代码是main()方法的第一行语句,所以此时StringPool中是空的,没有对象的  
        //于是它发现StringPool中没有内容为abc对象,接着它就会把abc对象放到StringPool中  
        //接下来它去执行new String("abc")构造方法  
        //我们知道:new关键字表示生成一个对象,这个对象是在Java的堆内存中的  
        //于是接下来它就在Java的堆内存中又生成一个内容为abc的对象  
        //这样就造成了StringPool中有一个abc对象,堆内存中也有一个abc对象  
        String s = new String("abc");  
          
        //【执行完该行代码,内存中不会生成新的对象】  
        //由于这里是通过直接给出字面值"abc",而不是new的方式为字符串赋值  
        //所以这种情况下,Java首先会到StringPool中查找有没有内容为abc的字符串对象存在  
        //若发现StringPool中没有abc对象,便在StringPool中新创建一个abc对象,再将引用指向新创建的abc对象  
        //如果在StringPool中存在abc对象,那么它就不会在StringPool中生成新的字符串对象了  
        //转而它会使用已经存在的字符串对象,并且将s1这个引用指向StringPool中的abc对象  
        String s1 = "abc";  
          
        //【执行完该行代码,内存中一共有三个对象】  
        //执行过程中,它会首先查看一下StringPool中有没有abc对象存在  
        //结果发现:有。。那么接着它就不会在StringPool中创建新的abc对象  
        //由于它是通过new String("abc")方式为字符串赋值的  
        //我们知道:只要Java中有new操作的话,就表示它会生成一个新的对象  
        //我们知道:而不管new多少次,都是生成新的对象,并且新的对象永远都在Java堆内存中  
        //所以执行该行代码时,它在堆内存中又会生成一个新的abc对象,并将其引用地址赋给s2  
        String s2 = new String("abc");  
          
        /** 
         * 也就是说,在执行完前面的三行语句后,内存中共有三个对象 
         * 其中包含了StringPool中的一个对象和堆内存中的两个对象 
         */  
          
        //对于Java中的==来说,它所比较的永远永远都是两个对象的内存地址  
        //换句话说,比较等号左右两边的两个引用是不是指向同样的一个对象  
        //对于那8个原生数据类型,==比较的是它们的字面值是不是一样的  
        //对于引用类型,则判断它们引用的地址是不是一样,即判断两个引用指向的是否是同样一个对象  
        //这里s、s1、s2分别指向三个不同的对象,这三个对象分别在内存中不同的地方  
        //所以s、s1、s2中任意两个使用==比较时,由于三者的内存地址均不同,故返回值都是false  
        System.out.println(s == s1);  
        System.out.println(s == s2);  
        System.out.println(s1 == s2);  
          
        System.out.println("~~~~~~飘逸的分隔线01~~~~~~");  
          
        System.out.println(s.equals(s1));  
        System.out.println(s.equals(s2));  
        System.out.println(s1.equals(s2));  
          
        System.out.println("~~~~~~飘逸的分隔线02~~~~~~");  
          
        /** 
         * ★当调用java.lang.String.intern()方法时★ 
         * 若StringPool中已经包含一个等于此String对象的字符串,则返回StringPool中的字符串 
         * 否则,将此String对象添加到StringPool中,并返回StringPool中的此String对象的引用 
         */  
          
        //【当调用s.intern()时】它首先会先查StringPool中是否存在内容为abc的对象          
        //结果发现:有。。这时它就会将s.intern()的返回值指向StringPool中的abc对象  
        //换句话说:s.intern()返回的是StringPool中的abc对象的地址,即与s1相等的值  
        //所以s == s.intern()的判断就相当于拿s和s1进行==判断,结果当然会返回false  
        //【当调用s1.intern()时】它还是会检查StringPool中是否存在内容为abc的对象  
        //结果发现:有。。这时它同样会将StringPool中abc对象的地址返回赋给s1.intern()的返回值  
        //而s1本身指向的就是StringPool中的abc对象,所以s1 == s1.intern()判断的结果即true  
        //【基于同样道理】s.intern()和s2.intern()的返回值都是StringPool中的abc对象的地址  
        //所以s.intern() == s2.intern()判断的结果亦为true  
        System.out.println(s == s.intern());  
        System.out.println(s1 == s1.intern());  
        System.out.println(s.intern() == s2.intern());  
          
        System.out.println("~~~~~~飘逸的分隔线03~~~~~~");  
          
        String hello = "hello";  
        String hel = "hel";  
        String lo = "lo";  
          
        //这种情况下,在使用加号操作时  
        //★如果★加号左右两边的操作数都是字面值(即常量值)的话  
        //那么它会将这两个字面值拼起来,并得到一个对象,然后检查StringPool中有没有该对象存在  
        //若StringPool中没有该对象的话,那么就把它放进去  
        //若StringPool中存在该对象的话,则不生成新的对象,而是直接返回StringPool中的该对象  
        //★如果★加号左右两边有一个操作数不是常量的话,即有一个是变量的话  
        //那么在将这两个操作数的值拼起来后,就不会检查StringPool而是直接在堆内存中生成新对象  
        //也就是说"hel" + "lo"最终会拼成"hello",并且它返回的是StringPool中hello的地址  
        //【所以hello == "hel" + "lo"判断的结果即为true】  
        //而"hel" + lo最终也会拼成"hello",但不同的是它所拼成的"hello"不是StringPool中的  
        //而是在Java堆内存中新生成的一个"hello"对象。既然一个在堆内存中,一个在StringPool中————————截至此处,有待商榷!!  
        //【所以二者肯定不是同一个对象,故hello == "hel" + lo判断的结果即为false】  
        //【同理hello == hel + lo判断的结果亦为false】  
        System.out.println(hello == "hel" + "lo");  
        System.out.println(hello == "hel" + lo);  
        System.out.println(hello == hel + lo);  
    }  
} 

 控制台输出如下

false  
false  
false  
~~~~~~飘逸的分隔线01~~~~~~  
true  
true  
true  
~~~~~~飘逸的分隔线02~~~~~~  
false  
true  
true  
~~~~~~飘逸的分隔线03~~~~~~  
true  
false  
false  

 

总结一下:

 

1、通过new关键字创建的对象是在堆上,与字符串常量池内存地址肯定不一样.
2、通过new String("sb"),如果在常量池中没有sb,则会新建这个sb对象放进去,然后再到堆中创建一个sb对象。这样就会有两个值均为sb的对象了。
3、通过直接赋值String s = 'sb',则会直接在常量池寻找是否存在这个sb,不存在则在常量池中创建,存在则直接返回这个sb在常量池中的内存地址,使引用变量s指向它。
4、String.intern()方法:'sb'.intern(),则会去常量池查询是否存在sb这个字符串对象,存在则直接返回内存地址,不存在则创建再返回内存地址,反正最后常量池中肯定会有这个sb字符串对象,而返回的结果也一定是常量池中的内存地址。

 

转自: http://blog.csdn.net/jadyer/article/details/5961747

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值