JAVA中String、StringBuilder、StringBuffer的区别以及用途

在使用java编程过程中我们最常使用的类无非就是String ,下面我们详细了解一下String在JDK中的实现以及分析

目录

 String类

String对象的创建方式

String类分析

StringBuffer、StringBuilder

总结 


 

 String类

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence 

String是一个final类 实现了Serializable、Comparable、CharSequence接口,String一旦创建便不可修改其指针指向内存的值,

大家或许说,我使用String不是经常在修改吗?那我看看修改String的简单过程 如Hello -> HelloWorld

 

其实只是引用的指向变为了另一个内存空间,并且新的内存空间的内容为修改后的值,在这里我们有疑问为什么会设计成为final类 即该类具有不可变性,不可变性会带来一定的效率问题,如使用 " + " 操作连接字符串时,会不断创建新的对象,如果存在大量拼接的情况这样会产生大量的垃圾对象,导致频繁GC,影响了整体服务性能

但是编译器可以让不可变的字符串共享,即如果String的内容一致,只需要复制多个引用即可实现共享,而不需要每次使用都创建一个新的对象,Java的设计者认为字符串共享带来的高效率远远胜过提取、拼接字符串所带来的低效率,此外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能大大提高,当然在线程安全性上也有相应的保证。

String对象的创建方式

首先看一下常量池的概念
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。

方式一  这种创建的方式是比较推荐的一种方式
首先会从字符串常量池中查找是否有该字符串,如果存在则将该指针复制一份给引用并返回,不存在则创建
这也是String为final类的一个好处,可以在常量池中共享给使用者

String str = "Hello";

方式二 不推荐
首先在java堆区创建String对象
然后从字符串常量池中查找是否有该字符串,如果不存在则创建一份

String str = new String("Hello")

简单看一下这两种方式的区别

String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
System.out.println(str1 == str2);//true
System.out.println(str1 == str3);//false

String str4 = "HelloWorld";
String str5 = "Hello" + "World";
String str6 = str1 + "World";
//因为字符串常量在编译时确定 所以Str5编译后为字符串常量"HelloWorld"
System.out.println(str4 == str5);//true 
//而Str1为变量,编译时不能确定,
System.out.println(str4 == str6);//false

使用new构造器创建字符串对象一定会开辟一个新的heap空间
而双引号则是采用了String interning(字符串驻留)进行了优化,效率比构造器高。

String类分析

  • 属性
    /** 该数组用于存储字符串 */
    private final char value[];

    /** 当前String对象的hash值 */
    private int hash; // Default to 0

        String内部维护的是一个char数组,数组用于存储字符,String的基本所有方法都是围绕这个数组进行,可以看做是String的核心,hash用于缓存当前String对象hash值

  • 方法 

   String重写了Object的equals方法,同一个String对象返回true或者String的内容相等(即value数组的内容是否一致)也返回true

//String 重写了 Object的equals方法
public boolean equals(Object anObject) {
        //首先判断对象是否相等 如果对象相等直接返回true
        if (this == anObject) {
            return true;
        }
        //然后判断对比对象是否为String类型,如果是,
        //则判断String内部char数组的元素是否完全一致,即字符串内容是否相同,
        //如果相同则返回true,否则返回false
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
 }

  String的hashcode实现

 //计算公式为s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
  }

hashcode到底有什么作用,还是直接看Object类的hashcode方法注释,大致意思是 在两个对象使用equal方法比较之后为true则hashcode的值也必须一致,hashcode可以为提升hash表的性能 (如hashmap)

StringBuffer、StringBuilder

String也存在局限性,也就是不可变性带来的性能问题,但JDK提供StringBuffer和StringBuilder来弥补String的不足,当我们有需求做大量字符串拼接时,使用String会带来很大的性能开销,这时候使用StringBuffer或者StringBuilder可以高性能的完成,StringBuffer、StringBuilder其内部同样使用value数组存储字符数据,和String的不同之处,它们不需要重复创建对象,只需要对内部value数组进行扩容来满足存储的需要,StringBuffer和StringBuilder唯一不同的是StringBuffer是线程安全的类,可以在多线程环境下不用考虑线程同步的问题,而StringBuilder则性能更好,它们完成的功能是一致的。

总结 

String的特点就是其不可变性、简单,在多线程环境中不用考虑线程安全问题,缺点是频繁的变更String的值会带来内存的开销,如有这种经常变化的情况,使用StringBuilder或者StringBuffer这样可以更高性能并且节省内存资源占用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值