Java中String、StringBuffer、StringBuilder


1. String

1.1 java.lang.String 类是不可变类

  • String表示字符串类型,属于引用数据类型,不属于基本数据类型。

  • 在java中随便使用双引号括起来的都是String对象。例如:“abc”,“def”,“hello world!”,这是3个String对象。

  • java中规定,双引号括起来的字符串,是不可变的,也就是说 “abc” 自出生到最终死亡,不可变,不能变成"abcd",也不能变成"ab"。

  • 在JDK当中双引号括起来的字符串,例如:“abc” “def” 都是直接存储在“方法区"的"字符串常量池"当中的。

  • 为什么SUN公司把字符串存储在一个“字符串常量池”当中呢。因为字符串在实际的开发中使用太频繁。为了执行效率,所以把字符串放到了方法区的字符串常量池当中。

注意:只要采用双引号赋值字符串,那么在编译期将会放到方法区中的字符串的常量池里,如果是运行时对字符串相加或相减会放到堆中(放之前会先验证方法区中是否含有相同的字符串常量,如果存在,把地址返回,如果不存在,先将字符串常量放到池中,然后再返回该对象的地址)。

示例代码:

public class StringTest01 {
    public static void main(String[] args) {
        // 这两行代码表示底层创建了3个字符串对象,都在字符串常量池当中。
        String s1 = "abcdef";
        String s2 = "abcdef" + "xy";

        // 凡是双引号括起来的都在字符串常量池中有一份。
        // new对象的时候一定在堆内存当中开辟空间。
        String s3 = new String("xy");

        // i变量中保存的是100这个值。
        int i = 100;
        // s变量中保存的是字符串对象的内存地址。
        // s引用中保存的不是"abc",是0x1111。
        // 而0x1111是"abc"字符串对象在“字符串常量池”当中的内存地址。
        String s = "abc";
    }
}

内存分析:
在这里插入图片描述

1.2 String s1 = “xxx” 和 String s2 = new String(“xxx”)

示例代码:

public class StringTest02 {
    public static void main(String[] args) {
        String s1 = "xyz";		// "hello"是存储在方法区的字符串常量池当中
        String s2 = "xyz";		// 这个"hello"不会新建。(因为已经存在了!)
        System.out.println("s1 = s2: " + (s1 == s2)); // true,双等号比较的是变量中保存的内存地址

        String x = new String("xyz");
        String y = new String("xyz");
        System.out.println("x = y: " + (x == y)); // false,双等号比较的是变量中保存的内存地址
        System.out.println("x equals y: " + (x.equals(y))); // true,字符串对象之间的比较不能使用“==”,应该调用String类的equals方法。

        System.out.println("s1 = x: " + (s1 == x)); // false
    }
}

运行结果:
在这里插入图片描述

内存分析:
在这里插入图片描述

  • 如果是采用双引号引起来的字符串常量,首先会到常量池中去查找,如果存在就不再分配,如果不存在就分配,常量池中的数据是在编译期赋值的,也就是生成 class 文件时就把它放到常量池里了,所以 s1 和 s2 都指向常量池中的同一个字符串 “xyz”。

  • 关于 x,y 采用的是 new 的方式,在 new 的时候存在双引号,所以他会到常量区中查找 “xyz”,而常量区中存在 “xyz”,所以常量区中将不再放置字符串,而 new 关键子会在堆中分配内存,所以在堆中会创建对象 xyz。

  • 如果比较 x 和 y 必须采用 equals(),String 已经对 eqauls 方法进行了覆盖。

1.3 两个 String 面试题

①下面代码创建了几个对象?

String s1 = new String("hello") ;
String s2 = new String("hello") ;

3个,堆中2个,方法区1个。所以使用 String 时,不建议使用 new 关键字,因为使用 new 可能会创建多个对象。

②String 为什么是不可变的?

String 类底层是一个byte[]数组,数组一旦创建长度不可变。而且这个数组被 final 修饰,被 final 修饰的引用一旦指向某个对象之后,不可再指向其它对象,所以 String 是不可变的!

1.4 String 常用方法

具体使用方法请参考帮助文档。

方法名描述
length()取得字符串的长度
isEmpty()判断字符串是否为空串
toCharArray()将字符串转换为字符数组
endsWith()判断字符串是否以指定的后缀结束
startsWith()判断字符串是否以指定的前缀开始
equals()字符串相等比较,不忽略大小写
equalsIgnoreCase()字符串相等比较,忽略大小写
indexOf()取得指定字符在字符串的位置
lastIndexOf()返回最后一次字符串出现的位置
replace()用新内容替换字符串中指定的内容
split()根据指定的表达式拆分字符串
substring()截子串
trim()去前后空格
valueOf()将其他类型转换成字符串
charAt()返回指定索引处的字符
compareTo()按字典顺序比较字符串
contains()判断是否包含某字符串
toLowerCase()将字符串所有字符转换为小写
toUpperCase()将字符串所有字符转换为大写

2. StringBuffer 和 StringBuilder

因为 String 是不可变对象,如果多个字符串进行拼接,将会形成多个对象,这样可能会造成内存溢出,会给垃圾回收带来工作量,所以频繁拼接字符串最好不要用 String。如果以后需要进行大量字符串的拼接操作,建议使用JDK中自带的:java.lang.StringBuffer、java.lang.StringBuilder

2.1 StringBuffer

StringBuffer 称为字符串缓冲区,它的工作原理是:预先申请一块内存,存放字符序列,如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列。StringBuffer 是可变对象,这个是 String 最大的不同。

示例代码:

public class StringBufferTest01 {
    public static void main(String[] args) {
        // 创建一个初始化容量为16个byte[] 数组(字符串缓冲区对象)
        StringBuffer sb1= new StringBuffer();

        // 拼接字符串,以后拼接字符串统一调用 append()方法
        sb1.append("a");
        sb1.append("b");
        sb1.append("d");
        sb1.append(3.14);
        sb1.append(true);
        // append方法底层在进行追加的时候,如果byte数组满了,会自动扩容。
        sb1.append(100L);

        System.out.println(sb1.toString());

        // 指定初始化容量的StringBuffer对象(字符串缓冲区对象)
        // 指定的大一点,这样可以减少底层的扩容次数,提高效率
        StringBuffer sb2 = new StringBuffer(100);
        sb2.append("hello");
        sb2.append("world");
        sb2.append("hello");
        sb2.append("kitty");

        System.out.println(sb2);
    }
}

运行结果:
在这里插入图片描述

2.2 StringBuilder

用法同 StringBuffer,但StringBuilder 和 StringBuffer 的区别是:

StringBuffer 中所有的方法都是同步的,是线程安全的,但速度慢;
StringBuilder 的速度快,但不是线程安全的。

2.3 一个面试题

StringBuilder / StringBuffer为什么是可变的呢?

StringBuffer / StringBuilder 底层实际上是 byte[] 数组,这个数组没有被final修饰,StringBuffer / StringBuilder 的初始化容量我记得应该是16,当存满之后会进行扩容,底层调用了数组拷贝的方System.arraycopy()…是这样扩容的。所以 StringBuilder / StringBuffer 适合于使用字符串的频繁拼接操作。


参考资料

微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值