您现在的位置是:首页 > 唯美句子

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

作者:往北时间:2024-04-04 13:50:37分类:唯美句子

简介  文章浏览阅读654次,点赞45次,收藏34次。由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。他们的底层原理与String类似,都是通过数组来完成对字符串的存储,其默认长度为16,当

点击全文阅读

   在之前的文章中我们曾简单介绍过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

 

     

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

点击全文阅读

郑重声明:

本站所有活动均为互联网所得,如有侵权请联系本站删除处理

我来说两句