String、StringBuilder和StringBuffer的区别

目录

一、String类

1.String类底层代码

2.String类的构造方法

3.String类字符串特点

4.理解String类值不可变性

5.创建字符串对象的区别对比

6.String类不同拼接方式区别

二、StringBuilder类和StringBuffer类

1.底层代码

 2.StringBuilder类和StringBuffer类的区别

三、String类、StringBuilder类和StringBuffer类异同

一、String类

1.String类底层代码

//String底层代码
public final class String implements java.io.Serializable, Comparable<String>, CharSequence, Constable, ConstantDesc {
        private final byte[] value;
}

由上述代码可以得出:

  • String类是由final修饰的类,因而不能被其他类继承;
  • String类底层是通过byte类型的数组实现的,也被final修饰,所以字符串的值在创建之后就不可以被修改。 

2.String类的构造方法

public String()创建一个空白字符串对象,不含有任何内容
public String(char[] chs)根据字符数组的内容,来创建字符串对象
 public String(String original)根据传入的字符串内容,来创建字符串对象
String s = “abc”直接赋值的方式创建字符串对象,内容就是abc

3.String类字符串特点

  • java 程序中所有的双引号字符串,都是String类型的对象
  • 字符串不可变,他们的值在创建后不能被更改
  • 虽然String的值是不可变的,但是他们可以共享

注意:所有字符串常量都会存在方法区的字符串常量池中

使用字符串字面量创建对象时,系统会检查该字符串是否在字符串常量池(方法区)存在,如果不存在,会创建,如果存在,不会重新创建而是直接使用。

4.理解String类值不可变性

class Demo {
    public static void main(String[] args) {
        String str1 = "hello";
        System.out.println(str1);
        String str2 = "hello";
        str1 = "world";
        System.out.println(str1);
        System.out.println(str2);
    }
}

内存图:

 解释:字符串str1和str2内容相同,都指向字符串常量池中的同一个地址001,它们共享字符串“hello”;str1值发生改变,系统会重新分配内存地址进行赋值,而原先的内存地址里面的值并没有发生变化,这就是string字符串的不变性。

5.创建字符串对象的区别对比

  • 构造方法创建

  ​    通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同。

  • 直接赋值方式创建

  ​    以“ ”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串常量池中维护。

面试题:使用String str = new String("hello")方式创建对象,一共创建几个对象?

答:一共会创建两个对象,一个是使用new创建的对象,存储在堆中;另一个是常量对象“hello”,存储在字符串常量池中。

6.String类不同拼接方式区别

class Demo {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "world";
        String str4 = "helloworld";
        String str3 = "hello"+"world";//常量优化机制
        String str5 = "hello"+str2;
        String str6 = str1+"world";
        String str7 = str1+str2;
        System.out.println(str4==str3);//true
        System.out.println(str4==str5);//false
        System.out.println(str4==str6);//false
        System.out.println(str4==str7);//false
    }
}

总结:

  • 常量优化机制,"hello"和"world"是字符串常量,在编译时,会直接拼接成字串"helloworld" ,因而和常量池中已创建的"helloworld"是同一个地址;
  • 当变量与字面量或变量与变量进行拼接时系统会在堆中创建一个StringBuilder对象,调用append()方法进行拼接,最后调用toString()方法转换成String对象,因str5、str6和str7都指向的是堆内存中String对象的地址值。

面试题:String s = new String(“1”)+ new String(“1”)创建了几个字符串对象?

答:创建了5个字符串对象。字符串常量池中创建字符串"1"对象,堆内存中开辟两个内存地址创建String对象,之后进行字符串拼接,系统会在堆中创建一个StringBuilder对象,调用append()方法进行拼接,最后调用toString()方法转换成String对象。

二、StringBuilder类和StringBuffer类

1.底层代码

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
@HotSpotIntrinsicCandidate
public StringBuilder() {
    super(16);
}
@HotSpotIntrinsicCandidate
public StringBuilder(int capacity) {
    super(capacity);
}
}
private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = value.length >> coder;
    int newCapacity = (oldCapacity << 1) + 2;
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
    return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}
  •  底层是用一个数组来存储字符串的值,默认长度为16,即一个空的StringBuiler和StringBuffer对象数组长度为16;
  • 若采用有参构造函数创建StringBuilder和StringBuffer对象,数组的长度不再是16,则根据当前对象的值来决定数组的长度,即长度为当前对象的值的长度+16。如果数组中的字符串的个数超出数组的长度,则会对数组进行扩容;
  • 扩容也就是创建一个新的byte数组,将现有的容量扩大一倍再加上2,扩容完成之后,将原数组的内容复制到新数组,最后引用指向新的byte数组。

 2.StringBuilder类和StringBuffer类的区别

线程安全是指在多线程环境下,多个线程同时访问同一资源,不会产生意外结果或导致数据出错的状态。

常用的线程安全方法:加锁。通过加锁机制控制对共享资源的访问,使得每次只有一个线程能够访问共享资源。Java中提供了synchronized关键字来实现加锁功能。

StringBuilder类:线程不安全,单线程。

StringBuffer类:线程安全,多线程。

StringBuffer类几乎所有公开的方法都是用synchronized修饰的,而StringBuilder没有。

三、String类、StringBuilder类和StringBuffer类异同

相同点:底层都是通过byte数组实现的

不同点:

1.String类对象创建之后,它的值不能修改,若要修改需要开辟新的内存空间来存储修改之后的对象;而StringBuilder类和StringBuffer类对象的值可以修改,不需要开辟新的内存空间;

2.StringBuffer类几乎所有公开的方法都是用synchronized修饰的,线程比较安全,在多线程系统中可以保证数据同步,只是效率低,而StringBuilder没有synchronized修饰,线程不安全,适合单线程。

总结:在实际开发中需要对字符串进行频繁的修改的,不使用String类;若要考虑线程安全的时候使用StringBuffer类;若不需要考虑线程安全,选择使用StringBuilder类。

  • 16
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值