字符串 String 类、 StringBuffer 类、StringBuilder 类

String 类

基本介绍

  • String 对象用于保存字符串,也就是一些字符序列
  • 字符串常量对象使用双引号括起来的字符对象,如“Jack”、“你好”等
  • 字符串的字符采用 Unicode 编码,一个字符(不论是字符还汉字)占两个字节
  • String 类有很多构造方法,如以下常用的几个:
    • String s1 = new String();

    • String s2 = new String(String original);

    • String s3 = new String(char[] a);

    • String s4 = new String(char[] a, int startIndex, int count);

    • String s5 = new String(byte[] b);

  • String 类实现了接口 Serializable ,所以 String 可以串行化(串行化的作用就是 String 可以在网络传播)
  • String 类实现了接口 Comparable ,所以 String 可以比较大小
  • String 是 final 类,所以不能被其他的类继承
  • String 类里有一个属性: private final char value[] 用于存放字符串内容(传递过来的字符串都放在 value 数组中), value 是用 final 修饰的,即 value 是一个常量,不可以修改(value 是一个数组,所以不可修改是指 value 的地址不可以修改,即 value 不可以再指向一个新的地址,但是数组的内容可以修改,即数组元素可以修改)
public class Test {
    public static void main(String[] args) {
        final char[] value = {'a','b','c'};
        value[0] = 'q'; // 数组元素可以修改
        char[] v = {'1','2','3'};
        // value = v; // 报错,数组的地址不能修改,即不能指向一个新的对象(地址)
    }
}

创建 String 对象的两种方式和区别

1、直接赋值 String s = "zs";        

  • 先从常量池查看是否有 "zs" 数据空间,如果有,直接让 s 指向该数据空间,如果没有则重新创建,然后让 s 指向创建的空间。 s 最终指向的是常量池的空间地址        

2、调用构造器 String s2 = new String("zs");

  • 先在堆中创建空间,里面维护了 value 属性,指向常量池的 "zs" 空间。如果常量池没有 "zs" ,就重新创建,如果有,直接通过 value 指向。s2 最终指向的是堆中的空间地址

内存分析图如下

 字符串的特性

  • String 类是 final 类,代表不可变的字符序列
  • 字符串是不可变的,一个字符串对象一旦被分配,其内容不可更改

例题1:以下语句创建了几个对象?

String s = "hello";

s = "haha";

答案:两个,内存示意图如下

例题2:以下语句创建了几个对象?

String s = "abc" + "def";

答案:一个,因为编译器会进行优化,判断创建的常量池对象是否有引用指向

String s = "abc" + "def"; 会优化成 ——> String s = "abcdef";

所以最终只创建了 “abcdef” 这一个对象

 例题3:

String a = "hello";

String b = "abc";

/*

* 根据 debug 的过程可以得到如下 String c = a + b 语句的执行流程

* 1、首先创建一个对象 StringBuilder sb = new StringBuilder();

* 2、然后在 sb 对象里追加 a 和 b 对应的字符串

* sb.append("hello");

* sb.append("abc");

* 3、最后根据 sb 对象生成一个 String 对象: String c = sb.toString();

* public String toString(){ // StringBuilder 里的 toString 方法源码

*      // value 存储的是 hello abc 字符序列

       return new String(value, 0, count);

  }

* 所以最后 c 其实指向的是堆中的 String 对象, String 对象里的 value[] 指向常量池中的 ”helloabc“

*/

String c = a + b;

内存分析图如下

 StringBuffer 类

基本介绍

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

  • StringBuffer 的直接父类是 AbstractStringBuilder,StringBuffer 实现了接口 Serializable ,即 StringBuffer 的对象可以串行化
  • 在父类 AbstractStringBuilder 中有属性 char[] value ,value 不是 final 修饰的,存放字符串内容,所以 StringBuffer 字符串是可变的,并且不是放在常量池中,而是放在堆中(因为 value 不是 final 常量)
  •  StringBuffer 是一个 final 类,不能被继承

String VS StringBuffer

  • String 保存的是字符串常量(放在常量池中),里面的值不能更改(因为 value 属性是一个 final 数组: private final char value[]),每次 String 类的更新实际上就是更改地址,效率较低。

  • StringBuffer 保存的是字符串变量(放在堆中),里面的值可以更改,每次 StringBuffer 的更新实际上是更新内容(因为 value 没有用 final 修饰: char value[]),不用每次更新地址(除非是内存空间不够了才会重新开辟更大的空间来存储原有的内容),效率较高。

 StringBuffer 构造器

public class Test {
    public static void main(String[] args) {
        // 由源码可知,创建了一个大小为 16 的 char[] ,用于存放字符序列
        StringBuffer s1 = new StringBuffer();

        // 由源码可知,创建了一个大小为 100 的 char[]
        StringBuffer s2 = new StringBuffer(100);

        // 由源码可知,创建了一个大小为 str.length + 16 的 char[]
        // 如以下创建了 5 + 16 = 21 的char[]
        StringBuffer s3 = new StringBuffer("hello");
    }
}

String 和 StringBuffer 的相互转换

public class Test {
    public static void main(String[] args) {
        // String -> StringBuffer
        String str = "hello";
        // 方式一:构造器
        StringBuffer s1Buffer = new StringBuffer(str);
        // 方式二: append() 方法
        StringBuffer s2Buffer = new StringBuffer();
        s2Buffer = s2Buffer.append(str);

        // StringBuffer -> String
        StringBuffer s3Buffer = new StringBuffer("world");
        // 方式一:使用 toString 方法
        String str1 = s3Buffer.toString();
        // 方式二:使用构造器
        String str2 = new String(s3Buffer);
    }
}

StringBuffer 的常用方法(一小部分)

  • 增: append
  • 删: delete
  • 改: replace
  • 查: indexOf
  • 插入: insert
  • 获取长度: length

这些方法的具体使用可以参考:     视频链接

StringBuilder 类

基本介绍

StringBuilder 是一个可变的字符序列,StringBuilder 类提供一个与 StringBuffer 兼容的 API (即 StringBuffer 类有的 API ,StringBuilder 都有),但不保证同步(StringBuilder 不是线程安全的)。 StringBuilder 类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(单个线程时不存在线程安全问题),如果是在单线程的情况下,建议优先采用 StringBuilder 类,因为在大多数实现中,它比 StringBuffer 更快

在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。

StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和 StringBuffer 一样

继承体系图如下:

 String 、 StringBuffer 、 StringBuilder 的比较

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值