【java】关于String、StringBuffer和StringBuilder的那些事

   在之前的文章中我们曾简单介绍过String这个引用类型变量,其实它还有许多特性,还有StringBuffer和StringBuilder这两个方法在字符串操作中也有非常重要的地位,接下来就由小编带大家梳理一下吧👊

ef22313ff90042009f01c78f367a4671.jpg

 

目录

一、String

1、构造方法

2、字符串的不可变性

3、字符串的比较

4、 String的常用方法:

二、StringBuider和StringBuffer

1、字符串的拼接

2、StringBuider与StringBuffer

总结

 


 

一、String

1、构造方法

String类提供的构造方式非常多,常用的就以下两种:
 
public static void main(String[] args) {
    // 使用常量串构造
    String s1 = "hello";
    System.out.println(s1);

    // 直接newString对象
    String s2 = new String("hello");
    System.out.println(s1);


}

注意:

1、String是引用类型,内部并不存储字符串本身

2. 在Java中“”引起来的也是String类型对象
那么这两种对象的存储方式有什么区别呢?
 
1c4580b6cc564e07b96a52f3b3b7382d.png
 

在s1使用常量串构造时,会直接在字符串常量池中创建字符串,在栈中直接存储字符串在字符串常量池中相应的位置

在s2通过new String对象的方式实例化字符串时,由于其字符串内容与s1一致,不会在常量池中创建新的对象,此时字符串对象存储在堆中,在堆中存储了对应字符在常量池中的位置

这样做有什么好处呢?就是所有的字符只用在字符串常量池中创建一次就行了,后续创建的相同的字符串只需引用对应的位置即可,大大提高了空间资源的利用效率

 

2、字符串的不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:
 
1. String 类在设计时就是不可改变的, String 类实现描述中已经说明了
        以下来自JDK1.8中String类的部分实现:
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[];

可以看出:

1. String类被final修饰,表明该类不能被继承
2. value被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
 
2. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

如在以下代码中:

String s1="hello";
String s2="hello";
s1="world";

5203648de539461c880b43d9a3c67fed.png

s1发生改变时,s2并不会改变指向,s1会重新分配内存地址进行赋值

String字符串具有不可变性,当字符串重新赋值时,不会在原来的内存地址进行修改,而是重新分配新的内存地址创建新的对象进行赋值

注意:

字符串不可变不是因为其内部保存字符的数组被final修饰了,因此不能改变。 不是因为String类自身,或者其内部value被final修饰而不能被修改。
final 修饰类表明该类不想被继承, final 修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内 容是可以修改的

 

3、字符串的比较

 

1. == 比较是否引用同一个对象
public static void main(String[] args) {
    int a = 10;
    int b = 20;
    int c = 10;

    // 对于基本类型变量,==比较两个变量中存储的值是否相同
    System.out.println(a == b); // false
    System.out.println(a == c); // true

    // 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
    String s1 = new String("hello");
    String s2 = new String("hello");
    String s3 = new String("world");
    String s4 = s1;
    System.out.println(s1 == s2); // false
    System.out.println(s2 == s3); // false
    System.out.println(s1 == s4); // true
}
注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。
2. boolean equals(Object anObject) 方法:按照字典序比较
字典序:字符在ASCII码中的顺序
 
public boolean equals(Object anObject) {
    // 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
        if (this == anObject) {
            return true;
        }
    // 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
        if (anObject instanceof String) {
    // 将anObject向下转型为String类型对象
            String anotherString = (String) anObject;
            int n = value.length;
    // 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
    // 4. 按照字典序,从前往后逐个字符进行比较
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
    }

 

3、int compareTo(String s) 方法 : 按照字典序进行比较
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

 

public static void main(String[] args) {
    String s1 = new String("abc");
    String s2 = new String("ac");
    String s3 = new String("abc");
    String s4 = new String("abcdef");

    System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1
    System.out.println(s1.compareTo(s3)); // 相同输出 0
    System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}

 

4. int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较
 
public static void main(String[] args) {
    String s1 = new String("abc");
    String s2 = new String("ac");
    String s3 = new String("ABc");
    String s4 = new String("abcdef");

    System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
    System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
    System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}

4、 String的常用方法:

6beff4d7f2f04770946eefe5118cf518.png

 

 


 

二、StringBuider和StringBuffer

1、字符串的拼接

让我们先来看一下下面这个问题:

public static void main(String[] args) {
    String s1 = "abc";
    s1=s1+"def";
    
    System.out.println(s1); 
   
}
//以上代码创建了几个对象?

答案是三个

b8902bd75d364a9f878f3cc7fa22c3be.png

        首先语句“String s1 = new String("abc");”会在字符串中创建一个对象"abc",在执行语句"s1=s1+"def";"时,会先创建一个对象“def”,然后在创建两个对象相加后的结果“abcdef”

这时我们发现看似简单的一个拼接操作,竟然需要创建三个对象,其效率可想而知是非常低下的,因此我们在平时应用中一般会避免这样直接通过“+”进行字符串的拼接。那么我们该怎么去拼接呢?这时候我们就要介绍StringBuider和StringBuffer了

 

2、StringBuider与StringBuffer

        由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。他们的底层原理与String类似,都是通过数组来完成对字符串的存储,其默认长度为16,当实例化一个StringBuider对象时,会根据创建字符串的长度来初始化内存,数组的内存为“创建字符的长度+16”,即在进行修改字符串的操作时有16个字符的空间可供操作,在对字符串进行修改时,会自动检测当前char数组是否装的下,如果超出数组范围,会对char数组进行扩容。
 
扩容机制:创建一个新的char数组对象,其长度一般为原数组的两倍,接着判断是否足够存储新的字符串,如果不够再进行扩容,以此类推,直到创建的数组足够存储新的字符串为止。然后将新字符串的内容存储到新数组,最后将指针指向新的数组

常用方法:

e68bd5e063b241cb83c0df47881a7f84.png

 

String和StringBuilder最大的区别在于 String 的内容无法修改,而 StringBuilder 的内容可
以修改。频繁修改字符串的情况考虑使用StringBuilder
 
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
  • String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
  • StringBuilder变为String: 调用toString()方法
 
 
【面试题】String、StringBuffer、StringBuilder的区别
  • String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
  • StringBuffer与StringBuilder大部分功能是相似的
  • StringBuffer大多数方法都使用了synchronized实现了同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

 

注意:在单线程的条件下,StringBuilder的运行效率要高于StringBuffer,因此在单线程的情况下一般选用StringBuilder,在多线程的情况下优先选用StringBuffer

 


总结

那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。作者还是一个萌新,如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊

b943785dc5844e63b6e407dfda9cc6e3.png

 

 
 
 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值