• JDK常用类解读--String


    一、字符串的不变性:

        文章使用的源码是jdk1.8的。(下同)

        1.首先可以看到`String`是`final`类,说明该类不可继承,保证不会被子类改变语义

        2.String的值实际上就是一个字符数组对象,字符数组成员变量`value`使用`final`修饰,说明该引用地址不变(不可指向其他对象)但是该数组对象本身是可以改变的,同时`value`使用private 修饰,String中也没有提供可以让外部访问该属性的方法,所有返回类型为String的方法,都只是返回了新的String对象,例如如substring

     

     

    以上的两点都是为了保证String的不变性,String类注释中有提到:

    * Strings are constant; their values cannot be changed after they
    * are created. String buffers support mutable strings.
    * Because String objects are immutable they can be shared.

      意思是字符串是常量,一旦创建对象,他们的值就无法改变,这里提到String buffers(StringBuffer StringBuilder)支持可变字符串,由于不可变的特性,使得字符串对象可以被共享;

    字符串被设计成不可变的原因(好处)

       1.首先就是就是类注释中有提到保证线程安全(不可被修改);是字符串常量池实现的前提,当代码中出现字面量形式(直接使用双引号)创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池(编译时就确定)中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,这大大节省了内存空间

       2.安全性的考虑;基本上所有的类中有会使用到String,最典型的就是HashMap,其中的key类型最适合String(重写了hashcode和equals),假如一个HashMap中元素的key可以被改变,可想而知必然会出现问题

       3.还有一点就是其HashCode方法,对结果进行了保存,就是第一次计算hash值,以后就不用重新计算了,提高运行效率,这也是HashMap中为什么使用String的原因之一

     

     

    二、字符串常量池

      首先我们知道创建字符串有两种方法:

        第一种直接使用字面量:String str = "hello";

        第二种就是使用new:String str = new String("hello");

    1.class常量池和运行时String常量池:

      当我们使用字面量创建字符串对象的时候如:"hello",java文件被编译成class文件时,"hello"会先检查class常量池是否存在相等的字符串,不存在就放入到class常量池;jvm运行时class文件被加载到内存中,同时class中的字符串常量池会被加载到运行时String常量池,所以当运行String str = "hello"语句时,首先会在运行时String常量池查找是否存在和"hello"相等的字符串对象(使用equals方法比较),存在就返回该对象的地址,不存在就在堆中new一个String对象,并返回该引用;

    2.intern方法:

      正常情况下运行时常量池是由class常量池决定的,换句话说在编译阶段就确定了运行时常量池的内容,不过String 提供了一个intern的本地方法,该方法可以在运行期间动态地在运行时常量池中添加String对象,当一个对象调用intern方法,首先会检查String常量池是否存在相等的String对象,存在则返回该对象,不存在则将该对象放入String常量池(jdk1.6 直接复制该对象到String常量池 1.7以后是加入该堆对象的引用) ,并返回该对象的引用。    

    测试代码:

    String str1 = "计算机";
    String str2 = "计算机";
    System.out.println("str1==str2:" + (str1 == str2));
    
    String str3 = new String("计算机");
    System.out.println("str1==str3:" + (str1 == str3));
    System.out.println("str1==str3.intern():" + (str1 == str3.intern()));
    System.out.println("str2==str3.intern():" + (str2 == str3.intern()));
    
    String str4 = new String("计算机");
    System.out.println("str3==str4:" + (str3 == str4));
    System.out.println("str3.intern()==str4.intern():" + (str3.intern() == str4.intern()));
    
     
    
    
    String str5 = new StringBuilder("软件").append("工程").toString();
    System.out.println("str5.intern() == str5:" + (str5.intern() == str5));
    
     
    
    String str6 = new String(new StringBuilder("物联网").append("工程").toString());
    System.out.println("str6.intern() == str6:" + (str6.intern() == str6));
    
     
    
    String str7 = new String("物联网");
    System.out.println("str7.intern() == str7:" + (str7.intern() == str7));
    
    //JDK1.8输出结果如下:
    
    str1==str2:true
    str1==str3:false
    str1==str3.intern():true
    str2==str3.intern():true
    str3==str4:false
    str3.intern()==str4.intern():true
    str5.intern() == str5:true
    str6.intern() == str6:true
    str7.intern() == str7:false
    
    
    //JDK1.7结果如下
    
    str1==str2:true
    str1==str3:false
    str1==str3.intern():true
    str2==str3.intern():true
    str3==str4:false
    str3.intern()==str4.intern():true
    str5.intern() == str5:true
    str6.intern() == str6:true
    str7.intern() == str7:false
    
    
    //JDK1.6结果
    
    str1==str2:true
    str1==str3:false
    str1==str3.intern():true
    str2==str3.intern():true
    str3==str4:false
    str3.intern()==str4.intern():true
    str5.intern() == str5:false
    str6.intern() == str6:false
    str7.intern() == str7:false

     看不懂,不理解的可以,欢迎评论哦!!!博主给你详细解答

     

      

     

  • 相关阅读:
    递归程序设计方法
    深入理解 Entity Framework
    面向对象设计的七大原则分析与实践
    JavaScript内置对象与原型继承
    设计模式之创建型(1)-简单工厂
    设计模式之创建型(2)-工厂方法模式
    设计模式之创建型(3)-抽象工厂模式
    设计模式之创建型(4)-建造者模式(Builder)
    设计模式之创建型(5)-单例模式(Singleton)
    设计模式之创建型(6)-原型模式(Prototype)
  • 原文地址:https://www.cnblogs.com/qzlcl/p/10852801.html
Copyright © 2020-2023  润新知