String、StringBuffer、StringBuilder

目录

1、String、StringBuffer与StringBuilder类关系

CharSequence

Appendable

2、String、StringBuffer与StringBuilder的异同

String

StringBuffer

StringBuilder

3、String为什么是不可变的?

4、为什么将String类型设计成不可变?

安全性

效率

5、String s = new String("abc");创建了几个对象?


【前言】

本篇博客将为大家介绍一下String、StringBuffer与StringBuilder的应用和它们之间的区别。

【内容】

1、String、StringBuffer与StringBuilder类关系

CharSequence

        是java.lang包下的一个接口,此接口对多种不同的char访问的统一接口,像String、StringBuffer、StringBuilder类都是CharSequence的子接口;

        CharSequence类和String类都可以定义字符串,但是String定义的字符串只能读,CharSequence定义的字符串是可读可写的;

        对于抽象类或者接口来说不可以直接使用new的方式创建对象,但是可以直接给它赋值;

Appendable

        表示实现此接口的子类可以对字符或字符串进行追加操作,StringBuffer和StringBuilder都实现了这个接口,它们可以进行字符序列的追加操作 ,而String没有实现此接口,因此它不能进行拼接操作,也就不能改变内容。

        此接口并没有规定多线程访问是否安全,要在子类中规定

2、String、StringBuffer与StringBuilder的异同

String

具有不可变性,它被声明为final class,所有属性也都是fina的。

它的拼接等方法都会产生新的String对象,然而并没有改变原来的String对象。

若对字符串频繁进行拼接操作,则对应用性能有明显影响。

因此,StringBuffer可以解决此问题。

StringBuffer

为解决String类拼接产生太多中间对象的问题而提供的一个类。

可以用append或者add方法,把字符串添加到末尾或指定位置。

是一个线程安全的可修改的字符序列。

虽然保证了线程安全,但同时也带来了额外的性能开销。

StringBuilder

能力和StringBuffer没有本质区别。

通过去掉线程安全的部分,有效减小了开销。

在不需要线程安全的情况下,使用StringBuilder进行字符串拼接的首选。

三者底层均采用char[]存储

3、String为什么是不可变的?

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

String类中使用字符数组保存字符串,有final修饰符,所以可以知道string对象是不可变的。

为了能更清楚理解String的不可变性,用一个例子来说明可能存在的误区:

String s = "abcde";              //假设s指向地址0x0001
System.out.println("s = " + s);
		
s = "123456";                    //重新赋值后,s指向地址0x0002,但0x0001地址中保存的值依然存在
System.out.println("s = " + s);

说明:s=“123456”执行后,s指向了新的地址

打印结果

s=abcde

s=123456

解析

String s = "abcde"执行之后

s = "123456"执行之后

因此,String的操作都是改变赋值地址,而不是改变值的操作。

但,如何保证s的引用地址不变,最终将输出的值变化呢?题目是这样的:

这个题目让你想到了什么?... 反射 本次题目使用反射可以解决。

public static void main(String[] args) {
	String s = new String("abc");
	// 在这中间可以添加N⾏代码,但必须保证s引⽤的指向不变,最终将输出变成abcd
	
    System.out.println("修改前s的内存地址" + System.identityHashCode(s));
    //获取String类的value字段
    Field value = s.getClass().getDeclaredField("value");
    //改变value属性的访问权限
	value.setAccessible(true);
	value.set(s, "abcd".toCharArray());
    System.out.println("修改后s的内存地址" + System.identityHashCode(s));
	System.out.println(s);
}

打印结果

可见s字符串序列已经被改变了,但是str的内存地址没有改变。

4、为什么将String类型设计成不可变?

主要基于安全性和效率两点考虑。

安全性

        因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。字符串本身是线程安全的。

        String被许多Java类用来当做参数,比如网络连接地址URl、反射机制所需要的的String参数,如果String不是固定不变的,将会引起各种安全隐患。

效率

字符串不变性保证了hash码的唯一性,不必每次都取计算新的哈希码。

        只有字符串是不可变的,常量池才得以实现。常量池是java堆内存中一个特殊的存储区域,当创建一个String对象,加入此字符串值已经存在与常量池中,则不会创建一个新的对象,而是引用已经存在的对象。

5、String s = new String("abc");创建了几个对象?

首先要看常量池里是否有“abc”这个字符串,如果有,则创建一个,如果没有,则创建两个。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值