美文网首页
理解 Java 的字符串,String、StringBuffer

理解 Java 的字符串,String、StringBuffer

作者: AD刘涛 | 来源:发表于2020-04-04 14:03 被阅读0次

    String 字符串

    String 是 Java 语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是 典型的 Immutable 类,被声明成为 final class ,所有属性也都是 final 的。也由于它的 不可变性 ,类似拼接、裁剪字符串等动作,都会产生 新的 String 对象 。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。

    String s1 = "Mr L";
    String s2 = s1;
    String s3 = new String(s1);
    System.out.println(s1 == s2); // true
    System.out.println(s1 == s3); // false
    

    为什么会这样?原因是s3使用 new String 时一定会在堆中重新创建一个内存区域,而 s2 则会直接使用了 s1 的引用,所以得到的结果也完全不同。

    特性:

    • String 是标准的不可变类(immutable),对它的任何改动,其实就是创建了一个新对象,再把引用指向该对象;
    • String 对象赋值之后就会在常量池中缓存,如果下次创建会判定常量池是否已经有缓存对象,如果有的话直接返回该引用给创建者。
    String 不可变性都有哪些好处?
    • 只有当字符串是不可变的,字符串常量池才能实现,字符串池的实现可以在运行时节约很多堆空间,因为不同的字符串变量都指向池中的同一个字符串;

    • 可以避免一些安全漏洞,比如在 Socket 编程中,主机名和端口都是以字符串的形式传入,因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞;

    • 多线程安全,因为字符串是不可变的,所以同一个字符串实例可以被多个线程共享,保证了多线程的安全性;

    • 适合做缓存的 key,因为字符串是不可变的,所以在它创建的时候哈希值就被缓存了,不需要重新计算速度更快,所以字符串很适合作缓存的中的 key。

    编译器对字符串的优化

    根据前面的知识我们知道,对于 String 的任何操作其实是创建了一个新对象,然后再把引用地址返回该对象,但 编译器也会对 String 进行特殊处理,以此来提供程序的运行效率,比如以下代码:

     String str = "hi," + "Mr L";
     String str2 = "hi,Mr L";
     System.out.println(str == str2); // true
    

    这就说明 编译器 在某些情况下会特殊处理 String 类型。

    字符串常量池

    字符串常量池是存储在 Java 堆内存中的字符串池,是为防止每次新建字符串带的时间空间消耗的一种解决方案。在创建字符串时 JVM 会首先检查字符串常量池,如果字符串已经存在池中,就返回池中的实例引用,如果字符串不在池中,就会实例化一个字符串放到池中并把当前引用指向该字符串,以上案例就是字符串常量池运用。

    字符串比较

    比较两个String对象的值是否相等,一定要用equals 方法

      String str = "hi," + "Mr L";
      String str2 = "hi,Mr L";
      System.out.println(str.equals(str2)); // true
    
    ==equals 的区别是什么?

    ==基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等

    String x = "string";
    String y = "string";
    String z = new String("string");
    System.out.println(x==y); // true
    System.out.println(x==z); // false
    System.out.println(x.equals(y)); // true
    System.out.println(x.equals(z)); // true
    

    因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String() 方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true

    StringBuffer

    StringBuffer为解决上面提到拼接产生太多中间对象 的问题而提供的一个类,我们可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本质是一个线程安全 的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是 StringBuilder

    StringBuilder

    StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBuffer 没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。

    相关文章

      网友评论

          本文标题:理解 Java 的字符串,String、StringBuffer

          本文链接:https://www.haomeiwen.com/subject/kccjphtx.html