• Java中字符串探索String ,StringBuffer ,StringBuilder及字符串缓存池


    字符串是编程中应用到最多的一个数据类型,简单实用,但是深入理解它们,会给我们带来更多好处。
     
    字符串缓存池:
        为了节省内存,提高资源的复用,java中引入了字符串缓存池的概念。
     
        缓存池中的字符串是不可回收的:
    在缓存池中的字符串是不会被垃圾回收机制回收的,基本都是常驻内存,所以过多食用String类,可能会出现内存溢出(下面会讲)。
     
        怎么样才会存进缓存池:
    1. 直接量赋值创建对象
      在Java,基本包装类型String,Long,Float,Boolean.......都可以利用直接量创建对象。
      String用直接量进行创建对象的时候,会先在缓存池找到字符串相同的对象,然后指向缓存池中该对象,这样就避免了重新为该对象分配内存,从而提高了复用,所以建议多用直接量去创建对象,这个也是上篇博文所推荐的。
    2. 调用构造器创建对象
      这种方法调用构造器,凡是new出来的对象都要进行内存分配,所以是不会指向缓存池之前已有的对象,这样就导致缓存池里面可能有多个值相同的String对象。
      
    package biaodashi;
    /**
     * 字符串关于缓存池
     * 
     * @author ccf
     * 
     */
    public class StringHuanCunChi {
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            StringHuanCunChi huanCunChi = new StringHuanCunChi();
             huanCunChi.test1();
           }
        public void test1() {
            String str1 = "ccf";
            String str2 = "ccf";
            String str3 = new String("ccc"); // new 会有新的地址分配,所以不会指向缓存池的"ccc"
            String str4 = new String("ccc");
            System.out.println("str1==str2?" + (str1 == str2));
            System.out.println("str3==str4?" + (str3 == str4));
        }
       }
    
    
    运行结果
    str1==str2?true
    str3==str4?false
    

      

     

    结果:看出str1 和str2都是指向同一个对象   而str3和str4就不是同一个对象了。


      怎么样才能指向缓存池已有的对象:
        
        
    要指向缓存池对象,改对象必须是直接赋直接量,也可以是多个直接量的运算值,而不能调用方法或者其他变量,但是被final修饰的可以进行宏替换的常量也可以看成直接赋值,因为以上这一些都能在加在类的时候,就被虚拟机计算出来其值。所以能指向缓存池。
    public void test1() {
            String str1 = "ccf";
            String str2 = "c" + "c" + "f";//三个直接量进行运算
            System.out.println("str1==str2?" + (str1 == str2));
            
    结果:str1==str2?true   多个直接量进行连接,也可以指向缓存池
    
        
    上面的代码中 String str2 = "c" + "c" + "f";一共创建了几个对象?????
    可能有人会说n个,但是其实只有一个,因为虚拟机对他们进行直接的计算,不需要创建对象,这也是使用直接量的好处。
    public void test1() {
            String str1 = "ccf" + "长度为:" + "3";
            String str2 = "ccf" + "长度为:" + str1.length();
            System.out.println("str1==str2?" + (str1 == str2));
            // 
    
    结果:  str1==str2?false 
    
    结论:str2调用了方法str1.length(),故不能再虚拟机加在类的时候就计算确定str的值,所以打印结果如下
    
    
        }
    
    public void test1() {
            final String length1 = "3";
            String length2 = "3";
            String str1 = "ccf" + "长度为:" + "3";
            String str2 = "ccf" + "长度为:" + length1;//调用final变量
            String str3 = "ccf" + "长度为:" + length2;//调用普通变量
            System.out.println("str1==str2?" + (str1 == str2));
            System.out.println("str1==str3?" + (str1 == str3));
        
    结果:  
    str1==str2?true
    str1==str3?false  
    可以得出结论:被final修饰的 length1效果是和直接量一样的,在虚拟机加在时候,length1是直接替换"3",之后就跟length1没关系了,效果可以说跟str1中一摸一样,这也是final变量和其他变量的不同之处,称为宏替换。
    

      

     
    关于String的不可变问题:
    String
    } 类是个不可变的类,创建对象后,不可以改变对象,但是日常代码经常对String进行操作,这对于String不可变这一说法是不是相悖了?
     
    看下这段代码:
    public void testString() {
            String str1 = "Hello";
            int OldId = System.identityHashCode(str1);
            str1 = str1 + " ccf!";//对字符串进行操作
            int NewId = System.identityHashCode(str1);
            System.out.println("OldId=" + OldId + "\nNewId=" + NewId);
               } 
    
    结果:
    OldId=854453928
    NewId=584020407 
    其中System.identityHashCode(str1);函数是打印出对象的HashCode,每个对象都有一个唯一的HashCode
    ,是对象的唯一标识,很明显,前后两个HashCode是不同的,
    

      

        得出一些结论:对String对象进行操作后,其返回的是一个新的对象,之前那个对象是没有改变的,改变的是str这个引用所指的对象,这时候的对象已经是新的对象,然而之前那个对象被废弃了,但是他存在缓存池,因此不会被垃圾回收机制回收,所以这里会出现内存泄漏,所以操作字符串,尽量不用String。
     
    但是StringBuffer和StringBuilder进行字符串操作的时候,就不会去new出现对象,引用的都是同一个对象,就可以减少String带来的弊端。
     
    public void testStringBuilder() {
            StringBuilder builder = new StringBuilder("Hello");
            System.out.println("ID=" + System.identityHashCode(builder));
            builder.append(" ccf!");
            System.out.println("ID=" + System.identityHashCode(builder));
            System.out.println(builder);
           
        } 
    结果:
    ID=854453928
    ID=854453928
    Hello ccf!
    

      


     
     
  • 相关阅读:
    【项目管理和构建】十分钟教程,eclipse配置maven + 创建maven项目(三)
    【项目管理和构建】——Maven下载、安装和配置(二)
    【项目管理和构建】——Maven简介(一)
    Maven 环境变量设置
    【BZOJ282】【洛谷P3829 】【SHOI2012】—信用卡凸包(凸包)
    【BZOJ1076】【SCOI2008】—奖励关(期望+状压dp)
    【BZOJ3687】—简单题(bitset)
    【BZOJ2118】—墨墨的等式(最短路+背包)
    【BZOJ4300】—绝世好题(二进制dp)
    【洛谷P3345】【ZJOI2015】—幻想乡战略游戏(动态点分治)
  • 原文地址:https://www.cnblogs.com/chenchuangfeng/p/2989324.html
Copyright © 2020-2023  润新知