StringStringBuffer和StringBuild

Posted brilliantZC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了StringStringBuffer和StringBuild相关的知识,希望对你有一定的参考价值。

一、String

1、特性

  • String字符串声明为final的,不可继承的。
  • String实现了Serializable接口,表示字符串是支持序列化的。实现了Comparable接口,表示String可以比较大小。
  • String内部定义了final char[] value用于存储字符串数据。
  • 通过字面量的方式(区别于new方式)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
  • 字符串常量池中是不会存储相同内容的字符串的。
  • String代表不可变的字符序列,简称:不可变性。主要体现在:
    1、当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
    2、当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
    3、当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
public class StringTest1 
    public static void main(String[] args) 
        String s1="abc";
        String s2="abc";
        s1="hello";
        System.out.println(s1);//hello
        System.out.println(s2);//abc
        System.out.println("*************");

        String s3="abc";
        s3+="def";
        System.out.println(s3);//abcdef
        System.out.println(s2);
        System.out.println("**************************");

        String s4="abc";
        String s5=s4.replace('a','m');
        System.out.println(s4);//abc
        System.out.println(s5);//mbc
        System.out.println("***********************");
    

String str = “abc”;  //str仅仅是一个引用对象,它指向一个字符串对象“abc”
str = “bcd”;  //让str重新指向了一个新的字符串“bcd”对象,而“abc”对象并没有任何改变

2、String的实例化方式

  1. 通过字面量定义的方式
  2. 通过new+构造器的方式
public class StringTest2 
    public static void main(String[] args) 
        //通过字面量定义的方式,此时的s1和s2的数据JavaEE声明在方法区中的字符串常量池中
        String s1="javaEE";
        String s2="javaEE";

        //通过通过new+构造器的方式,此时的s3,s4保存的地址值,是数据在堆中开辟空间以后对应的地址值
        String s3=new String("javaEE");
        String s4=new String("javaEE");

        System.out.println(s1==s2);//true
        System.out.println(s3==s4);//false
        System.out.println(s1==s3);//false
        System.out.println(s2==s4);//false

        String s5="javaEE";
        String s6="hadoop";
        String s7="javaEEhadoop";
        String s8="javaEE"+"hadoop";
        String s9=s5+"hadoop";
        String s10="javaEE"+s6;
        String s11=s5+s6;

        System.out.println(s7==s8);//true
        System.out.println(s7==s9);//false
        System.out.println(s7==s10);//false
        System.out.println(s9==s10);//false
        System.out.println(s9==s11);//false
        System.out.println(s10==s11);//false

        String s12=s9.intern();//返回值得到的s12使用的常量值中已经存在的“JavaEEHadoop”
        System.out.println(s7==s12);//true
    

结论:

  1. 常量与常量的拼接结果在常量池,且常量池中不会存在相同内容的常量
  2. 只要其中有一个变量,结果就放在堆中
  3. 如果拼接的结果调用inter()方法,返回值就在常量池中

3、String常用方法

int length():返回字符串的长度
char charAt(int index):返回指定索引处的字符
boolean isEmpty():判断字符串是否为空
String toLowerCase():将字符串中的所有字符转换为小写
String toUpperCase():将字符串中的所有字符转换为大写
String trim():返回字符串的副本,去掉前导空白和尾部空白,中间的空白不会被去掉
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString):忽略大小写,比较字符串的内容是否相同
String concat(String str):将指定字符串连接到此字符串的结尾,等价于用“+int compareTo(String anotherString):比较两个字符串的大小
String substring(int beginIndex):返回从beginIndex到末尾的子字符串
String substring(int beginIndex, int endIndex):返回从beginIndex到endIndex前一位的子字符串,不包括endIndex

boolean endsWith(String suffix): 判断字符串是否以指定的后缀结束
boolean startsWith(String prefix):判断字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset):判断字符串在指定索引开始的子字符串是否以指定前缀开始
boolean contains(CharSequence s):判断当前字符串中是否包含指定的字符串

int indexOf(String str):返回指定子字符串在当前字符串中第一次出现处的索引
int indexOf(String str, int fromIndex):返回从指定的索引后,指定子字符串在当前字符串中第一次出现处的索引
int lastIndexOf(String str):返回指定子字符串在当前字符串中最后一次出现处的索引
int lastIndexOf(String str, int fromIndex):返回从指定的索引后,指定子字符串在当前字符串中最后一次出现处的索引
注:indexOf和lastIndexOf方法如果未查找到指定子字符串时,返回值都为-1String replace(char oldChar, char newChar):替换当前字符串中指定的子字符串
String[] split(String regex):根据指定的符号拆分当前字符串,然后返回一个String数组

4、String与基本数据类型、包装类之间的转换

public class StringTest4 
    public static void main(String[] args) 
        /*
        Sring----->基本数据类型、包装类:调用包装类的静态方法:parseXxx(str);
        基本数据类型、包装类------->String:调用String重载的valueOf(xxx)
         */
        String s="123";
        //int n=(int)s  ;   错误的
        int num=Integer.parseInt(s);
        String s2=String.valueOf(num);//"123"
    


public class StringTest4 
    public static void main(String[] args) 
        /*
        String--->char[] :调用String的toCharArray()
        char[]---->String :调用String的构造器
         */
        String s="abc123";
        char[] charArray = s.toCharArray();
        for (int i = 0; i <charArray.length ; i++) 
            System.out.println(charArray[i]);
        
        char[] arr='h','l','l','o';
        String s1=new String(arr);
        System.out.println(s1);
    


public class StringTest4 
    public static void main(String[] args) 
        /*
        String---->byte[]:调用String的getBytes()
        byte[]----->String :调用String的构造器
         */
        String s="abc123";
        byte[] bytes = s.getBytes();
        System.out.println(Arrays.toString(bytes));//[97, 98, 99, 49, 50, 51]

        String s1 = new String(bytes);
        System.out.println(s1);  //abc123
    


二、StringBuffer和StringBuilder

  StringBuffer、StringBuilder和String类似,底层也是用一个数组来存储字符串的值,并且数组的默认长度为16,即一个空的StringBuffer对象数组长度为16。实例化一个StringBuffer对象即创建了一个大小为16个字符的字符串缓冲区。但是​当我们调用有参构造函数创建一个StringBuffer对象时,数组长度就不再是16了,而是根据当前对象的值来决定数组的长度,数组的长度为“当前对象的值的长+16”。所以一个 StringBuffer 创建完成之后,有16个字符的空间可以对其值进行修改。如果修改的值范围超出了16个字符,会先检查StringBuffer对象的原char数组的容量能不能装下新的字符串,如果装不下则会对 char 数组进行扩容。

StringBuffer扩容操作:
  扩容的逻辑就是创建一个新的 char 数组,将现有容量扩大一倍再加上2,如果还是不够大则直接等于需要的容量大小。扩容完成之后,将原数组的内容复制到新数组,最后将指针指向新的 char 数组。

String str=new String(); //new char[0]
String str1=new String("abc") ; //new char[]'a','b','c'

StringBuffer sb=new StringBuffer(); //char[] value=new char[16];底层创建了一个长度为16的数组
sb.append('a');  //value[0]='a';
sb.append('b');  //value[1]='b';

StringBuffer sb1=new StringBuffer("abc"); //char[] value=new char["abc".length()+16];

StringBuffer和StringBuilder中常用的方法:

StringBuffer append(xxx):拼接字符串
StringBuffer delete(int start,int end):删除指定范围的内容,左开右闭
StringBuffer replace(int start, int end, String str):替换指定范围的内容
StringBuffer insert(int offset, xxx):在指定位置插入指定的内容
StringBuffer reverse() :把当前字符序列逆转

public int indexOf(String str) : 返回指定子字符串在当前字符串中第一次出现处的索引
public String substring(int start,int end) :返回指定范围的子字符串
public int length() : 返回字符串的长度
public char charAt(int n ) : 获取指定索引处的字符
public void setCharAt(int n ,char ch) : 设置指定索引处的字符

三、String、StringBuffer和StringBuilder的异同

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

  1. String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
  2. StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
  3. StringBuffer使用了缓存区,StringBuilder没有使用缓存区,所以没有修改数据的情况下,多次调用StringBuffer的toString方法获取的字符串是共享底层的字符数组的。而StringBuilder不是共享底层数组的,每次都生成了新的字符数组。
  4. 因为方法被上锁,所以StringBuffer的性能一般会比StringBuilder差,单线程中建议使用StringBuilder。
  5. String对象的相加底层调用的是StringBuilder对象,分别调用了append方法和toString方法,所以在大量字符串相加时,使用String对象相加效率低于使用StringBuffer和StringBuilder,因为还有有StringBuilder对象的创建过程和toString方法中字符数组的拷贝过程。

以上是关于StringStringBuffer和StringBuild的主要内容,如果未能解决你的问题,请参考以下文章

StringStringBuffer和StringBuild

StringStringBuffer和StringBuild

StringStringBuffer和StringBuild

StringStringBuffer和StringBuilder比较

StringStringBuffer和StringBuilder区别及性能分析

stringstringbuffer和stringbuilder的区别