String,StringBuffer和StringBuilder

196 阅读6分钟

1.String类

1.1.基本介绍

  • String类的对象用于保存字符串(一组字符序列) ,将字符序列用双引号括起来就是字符串常量,如:"abc","你好"
  • 字符串中的字符使用Unicode字符编码,一个字符不管是字母还是汉字,都占两个字节(char)

1.2.创建String类的对象

  • 方式一: 直接赋值(字面量):
String s = "Java";

先从字符串常量池中查看是否有"java"的数据空间,如果有直接将value[]数组指向该数据空间的地址;如果没有则创建后指向;s -> value[] -> "java"在常量池中的地址

字符串常量池中不允许存放两个相同的字符串常量;

jdk7之前:字符串常量池在方法区中

image.png jdk7及之后:字符串常量池在堆空间中

image.png

  • 方式二:调用构造器:
//String类常用的构造方法(体现了方法的重载)

String s = new String();//String() 

String s1 = new String("Hello");//String(String original)

char[] c = {'j','a','v','a'};

String s2 = new String(c); //String(char value[])

String s3 = new String(c, 0, 3);//String(char value[], int offset, int count)

输出后:

String s = new String("Java");为例:

先在堆中创建空间,里面有String类用于存放字符串属性(value[]数组),s 指向 value[] 的地址;常量池中如果有"Java",则直接通过value[]指向其地址,没有则重新创建后再指向。

注意:s最终指向的是堆中value[] 的地址空间(区别与第一种方式)

image.png

1.3.String类细节

  • String类是final,代表不可变的字符序列,不能被其他类继承

  • String类实际上是利用属性 private final char value[] 这个字符类型数组来存放字符串

    • jdk9之后,为了节省内存空间,使用private final byte[] value作为存储字符串数据的容器
  • String类重写了equals方法,用于判断字符串内容是否相同

  • String类相加重要规则: 如果是常量相加,看的是常量池,如果是变量相加,则看的是堆。

    • 常量 + 常量 :结果仍在常量池;此时的常量可能是final修饰

      常量 + 变量 / 变量 + 变量 :会在堆中new一个String对象返回其地址

      调用intern()方法返回字符串常量池中字面量的地址

    • 执行代码String s = "Hello" + "Java";时,编译器会判断创建的常量池对象是否有引用指向,所以只会创建一个"HelloJava"对象,"Hello""Java"对象会被丢弃

    • String变量相加如下面代码

String a = "Hello";

String b = "Java";

String c = a + b;

则会创建HelloJavaHelloJava三个常量对象

  • 不可变性的理解:
    • 当对字符串变量重新赋值时,需要重新指定一个字符串常量的位置(新的常量池地址),不能在原有位置修改,原字符串常量仍存在
    • 当对原有字符串进行拼接或者replace()操作时,都需要重新开辟空间保存新的字符串,原有字符串不能修改

image.png

1.4.String类的常用方法

  • equals区分大小写判断内容是否相等
  • equalsIgnoreCase忽略大小写判断内容是否相等
  • length获取字符串的长度
  • indexOf获取指定字符或子串在字符串中第一次出现索引,找不到返回-1
  • lastIndexOf获取指定字符在字符串中最后一次出现索引,找不到返回-1
  • substring截取指定范围的子串
public static void main(String[] args) {

    String s = "Hello,Java~";

    System.out.println(s.substring(5));//从索引5开始截取后面的所有内容

    System.out.println(s.substring(0,5));//从索引0开始截取长度为5的子串

}

  • trim去除前后空格
  • charAt获取指定索引处的字符
  • toUpperCase转换成大写
  • toLowerCase转换成小写
  • concat拼接字符串
  • replace替换字符串中的字符
  • split根据指定的字符分割字符串(可以赋给一个数组)(分割时如果有特殊字符需加入转义字符)
  • toCharArray转换成字符串数组
  • compareTo逐位比较两字符串大小,前者大返回整数,后者大返回负数,相等返回零
  • format格式化字符串

2.StringBuffer

2.1.基本介绍

StringBugger代表可变的字符序列,可以对字符串内容进行增删,很多方法和String类相同,但StringBuffer的长度是可变的。StringBuffer同时也是一个容器。

2.2.创建StringBuffer对象

//创建一个容量为16的字符串缓冲区(char[]数组)存放字符串

StringBuffer sb = new StringBuffer();

//将参数中的字符串存入缓冲区,容量为当前字符串长度加16

StringBuffer sb1= new StringBuffer("Java");

//创建指定容量大小的字符串缓冲区

StringBuffer sb2 = new StringBUffer(100);

2.3.StringBuffer细节

  • StringBuffer继承了父类AbstractStringBuffer的属性char[] value(不是final),所以字符串中的内容是存放在堆中的( value指向堆中的字符数组地址)
  • StringBuffer是一个final类,不能被继承
  • 扩容机制,默认创建新的容量为:原容量 * 2 + 2 的数组,将原有value数组中的元素复制到新数组

2.4.StringBuffer常用方法

  • append增加字符
  • delete(start,end)按索引删除字符
  • replace(start,end,string)用string替换索引范围的子串
  • indexOf(string)查找子串在字符串第一次出现的索引,找不到返回-1
  • insert(int,string)在索引处插入指定字符串
  • length获取长度

2.5.String 对比 StringBuffer

  • String保存的是字符常量,里面的值不能更改String类的对象每次更新都是更改地址(创建新对象) ,效率较低。
  • StringBuffer保存的是字符串变量,里面的值可以更改,每次更新时可以直接改变值,不用更新地址。

2.6.String和StringBuffer的转换

  • String -> StringBuffer
String str = "Java~";

//方式1  使用构造器

StringBuffer sb = new StringBuffer(str);

//方式2  使用append方法

StringBuffer sb1 = new StringBuffer();

sb1 = sb1.append(str);
  • StirngBuffer -> String
StringBuffer sb2 = new StringBuffer("Java~");

//方式2  使用构造器

String s = new String(sb2);

//方式1  使用StringBuffer的toString方法

String s1 = sb2.toString();

3.StringBuilder

3.1.基本介绍

StringBuilder也是一个可变的字符序列,在字符串缓冲区被单个线程使用,可以作为一个简易的StringBuffer大多情况下StringBuilderStringBuffer,所以建议优先使用StringBuilder。但此类有线程安全问题,使用时需注意。

3.2.StringBuilder主要方法

StringBuilderStringBuffer方法是一样的。主要使用appendinsert方法,可以重载这些方法用来接收任意类型的数据

3.3.StringBuilder细节

  • StringBuilderfinal类,不能被继承
  • StringBuilder也继承了父类AbstractStringBuilder的属性char[] value来存放数据,所以字符序列也在堆中
  • StringBuilder的方法都没有做互斥的处理(synchronized关键字),所以在单线程的情况下才使用

4.三者对比

String不可变字符序列效率低,但是复用率高(一个字符串可以被无限使用)
StringBuffer可变字符序列效率高,线程安全
StringBuilder可变字符序列效率最高,线程不安全
  • String类如果多次执行改变串内容的操作,会导致大量没有引用字符串对象留在常量池中,降低效率;所以要对字符串做大量修改时,使用StringBuilder(单线程时优先选择)和StringBuffer,不使用String
  • 在字符串对象无需频繁修改,被多个对象引用时,使用String效率更高。