String,StringBuilder,StringBuffer区别

前言

这篇文章主要简单的介绍了StringStringBufferStringBuilder的区别,并不去刨析底层级

String

初学Java经常会误认为String是Java基本类型,实际上String并非Java基本类型,String本质上是对char数组的封装

//用来存字符串,字符串的本质,是一个final的char型数组 
private final char value[];  
                                        
//缓存字符串的哈希 
private int hash;    // Default to 0    
                             
//实现序列化的标识 
private static final long serialVersionUID = -6849794470754667710L;

/**
* 构造方法
* 实质上String 的创建是划分内存,创建字符数组
* Arrays.copyOf()实际调用底层System.arraycopy方法,进行内存划分
**/ 
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

这里需要注意的重点是:
private final char value[]这是String字符串的本质,是一个字符集合,而且是final的,是不可变的

String类实现的接口

在这里插入图片描述

Serializable接口Comparable接口大家都比较熟悉,一个是序列化接口,一个是比较able类接口,分别对应

	//序列化标记号
	private static final long serialVersionUID = -6849794470754667710L;

	// 内部比较方法
	public int compareTo(String anotherString) {
	   int len1 = value.length;
	   int len2 = anotherString.value.length;
	   int lim = Math.min(len1, len2);
	   char v1[] = value;
	   char v2[] = anotherString.value;
	
	   int k = 0;
	   while (k < lim) {
	       char c1 = v1[k];
	       char c2 = v2[k];
	       if (c1 != c2) {
	           return c1 - c2;
	       }
	       k++;
	   }
	   return len1 - len2;
	}

CharSequence接口这里我们得看一下,为什么常用的String类型不能算是基本类型?

在这里插入图片描述

根据String的定义来看,字符序列实际的体现就是String实际内容是char型数组只读体现在final上final描述的属性是常量属性,对于数组来说,其数组引用无法改变。对于这方面的讨论,之后会有详细的讨论。

CharSequence提供了如下方法:

在这里插入图片描述
在这里插入图片描述

这4种方法也常用到其中subSequence的实际实现就是调用了subString方法

在这里插入图片描述

此处的toString方法是将实现该接口的对象提供可转换为字符序列的方法,虽然命名上与Object的toString方法重复,但从理念上是不同的

在这里插入图片描述

通过上面我们可以知道的重点是:

  • String是一个final类,既不能被继承的类;
  • String类实现了java.io.Serializable接口,可以实现序列化
  • String类实现了Comparable,可以用于比较大小(按顺序比较单个字符的ASCII码);
  • String类实现了CharSequence接口,表示是一个有序字符的序列,因为String的本质是一个char类型数组

现在让我们创建一个String对象,并操作它,看看可以发现什么:

在这里插入图片描述
在上图中我们可以看到,在我创建了一个String类对象之后的HashCode值和我操作之后的HashCode值是不同的,这说明该类型的值是不可变的,这就意味着我每一次操作这个字符串对象都会生成一个新的String对象,然后将指针指向这个新的对象,然后就可以用原来声明的变量名来访问操作后的这个字符串对象。所以,如果需要大量的操作字符串的话,不建议使用String类型,因为它会大量的产生新的对象,GC就会工作,这就会影响性能

String常用方法介绍

返回指定位置的字符,从0开始记

public char charAt(int index) 

返回指定位置的字符的unicode编码,从0开始记

public int codePointAt(int index)

返回指定位置前一位的字符的unicode编码,从0开始记,其实也可以理解为指定位置字符unicode编码,从1开始记

public int codePointBefore(int index)

查询范围 endIndex-beginIndex
endIndex范围取 0~ length
endIndex范围取 0~ length + 1

public int codePointCount(int beginIndex, int endIndex)

比较大小
从首位开始比较,若不同输出 s - anotherString 值
相同输出0

public int compareTo(String anotherString)

比较大小忽略大小写

public int compareToIgnoreCase(String str)

合并字符串
相当于append

public String concat(String str)

替换字符串

public String replace(char oldChar, char newChar)

正则表达式匹配

public boolean matches(String regex)

判断是否包含
CharSequence接口String及其配套类(StringBuffer、StringBuilfer)实现

public boolean contains(CharSequence s)

替换 正则表达式匹配到的第一个 字符串

public String replaceFirst(String regex, String replacement)

替换 正则表达式匹配到的所有字符串

public String replaceAll(String regex, String replacement)

替换字符串中 target 为 replacement

public String replace(CharSequence target, CharSequence replacement)

StringBuffer 和 StringBuilder

StringBufferStringBuilder都继承了AbstractStringBuilder ,实际存储方式取消了final修饰符,所以StringBuffer和StringBuilder的字符数组长度可变且可以重新赋值


// 与String相比,减去了Comparable接口,两个都继承了AbstractStringBuilder

/***
 * StringBuffer
 */
public final class StringBuffer extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence {

/***
 * StringBuilder
 */
public final class StringBuilder extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence {

// AbstractStringBuilder的定义如下,其增加了Appendable,对应的就是append方法
abstract class AbstractStringBuilder implements Appendable, CharSequence
// 实际字符数组存储
char[] value;

为了给StringBuilderStringBuffer提供 + 的功能,AbstractStringBuilder通过Appendable接口提供了append方法

在这里插入图片描述

/**
 * 属性,Char 数组
 */
char[] value;

/**
 * 属性,标记数组长度
 */
int count;

/**
 * 无参数构造方法,子类 序列化必须提供
 */
AbstractStringBuilder() {

}

/**
 * 创建一个指定容量的char数组
 */
AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}


// StringBuffer和StringBuilder都是通过调用父类的构造方法进行构造,默认申请16个长度
public StringBuffer() {
    super(16);
}

/**
 * 自定义长度申请
 */
public StringBuffer(int capacity) {
    super(capacity);
}

StringBufferStringBuilder实现capacity变换长度是如何实现的呢?,我还是先dug

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

String BufferStringBuilder主要的区别在于,StringBuffer是线程安全的StringBuilder非线程安全的

String Buffer

在这里插入图片描述

由此可见,在我创建了一个StringBuffer类对象之后的HashCode值和我操作之后的HashCode值是相同的,这说明该类的值是可变的,每次的操作都是对对象本身操作,所以不会引发像String一样的问题。
所以在需要大量操作字符串的时候,建议使用StringBuffer来创建字符串对象。
然后让我们来看一看StringBuffer类中的append()方法
在这里插入图片描述

StringBuilder

在这里插入图片描述

由此可见,该类的值也是可变的,其实StringBuilder类是在 Java 5 中被提出,该类与StringBuffer最大的区别在于,StringBuilder中的方法没有被synchronized关键字修饰,不是线程安全的。

在这里插入图片描述

总结

1.String、StringBuffer、StringBuilder比较。

三者共同之处:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被参数修改影响到其他的应用。

  1. String:值不可变,影响性能,在对字符串操作较少、单线程情况下使用
  2. String实现了三个接口:SerializableComparable<String>CarSequence
  3. StringBuffer:值可变,线程安全,在对字符串操作较多、多线程情况下使用
  4. StringBuilder:值可变,线程不安全,在对字符串操作较多、单线程情况下使用
  5. StringBufferStringBuilder两者共同之处:可以通过append、indert进行字符串的操作
  6. StringBufferStringBuilder只实现了两个接口SerializableCharSequence,相比之下String的实例可以通过compareTo方法进行比较,其他两个不可以。

2.运行速度。

执行速度由快到慢:StringBuilder > StringBuffer > String

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值