String、StringBuffer以及StringBuilder类的相关说明

1.String为什么是一个不可变类?

  1. 该类一旦初始化,其值不变,因为该类使用final修饰(final的用法说明,请看下面注)
  2. 并且用于存储数据的是使用char类型的数组存储,并且该成员变量使用final修饰,没有提供公共的setter和getter方法
	public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

2.String不可变类的好处?

  1. 可以作为形式参数,该String类型的引用变量不变,那么使用他的Hash值则只需要计算一次就可以了,不需要重复计算并且值唯一,例如作为HashMap中的key值可以保证唯一性
  2. 可以作为StringPool中的值,即为常量池中的值,如果该值在常量池中有,那么直接使用,不需要重复创建
  3. String经常作为参数,String不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果String是可变的,那么在网络连接过程中,String被改变,改变String对象的那一方以为现在连接的是其他主机,而实际情况却不一定是。
  4. String的安全性,String的不可变性,可以在多线程中使用。

3.String是不可变类,那么String a=“Hello”+“Word”+"!!!"或者String a=“Hello” +new String(“Word !!!”)岂不是+或者+=改变了该类的不可变性?如果没有那么如何处理的那?;

首先对于String a=“Hello”+“Word”+"!!!"这个字符串编译会帮我们处理成String a=“Hello Word !!!”;因此还是保证了该类的不可变性。下面是反编译的结果可以看出

0 ldc #2 <Helloword!!!>
 2 astore_1
3 return	

对于String a=“Hello” +new String(“Word !!!”)这个字符串,java虚拟机会创建一个StringBuilder对象,然后通过appand方法将字符串存储到自己的数组中,然后通过toString方法返回给a因此+号是不违反不可变类特性的。以下是反编译代码

 new #3 <java/lang/StringBuilder>
 6 dup
 7 invokespecial #4 <java/lang/StringBuilder.<init> : ()V>
10 ldc #5 <Hello>
12 invokevirtual #6 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
15 new #7 <java/lang/String>
18 dup
19 ldc #8 <word !!!>
21 invokespecial #9 <java/lang/String.<init> : (Ljava/lang/String;)V>
24 invokevirtual #6 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
27 invokevirtual #10 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
30 astore_2
31 return

4.那么对于String a=new String(“Hello Word !!!”)和String a=“Hello Word !!!” 分别创建几个对象?在这里插入图片描述

  1. String a="Hello Word !!!“首先会看StringPool中是否存在"Hello Word !!!”,如果不存在那么会在StringPool中创建并分配地址,然后将栈中的a指向StringPool中的地址值。
  2. String a=new String(“Hello Word !!!”)首先会判断Stringpool中是否存在该字符串,如果存在,那么会在堆中分配该字符串的地址,然后该地址指向StringPool中的地址,最后栈中的a指向堆中分配资源的地址。
    所以使用equals方法比较的是内容是否相同,因此返回true,但是==比较的是内存地址值是否相同,因此返回是false。一个是堆中的地址值一个是StringPool中的地址值

5.String a=“Hello Word !!!” 和String a=new String(“Hello Word !!!”) 采用equals和==比较的结果值如何以及原因?

通过4的分析可以看出==比较时地址值是不同的,所以返回的是false;equals比较的是值是否相同,因此返回的是true,因为String对Object类中对equals方法进行了重写。

5.StringBuilder是什么?##

  1. StringBuilder是字符串的缓存类,因此是可变的
	public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

2.是通过append方法追加到字符数组中的。

  @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

6.String和StringBuilder以及StringBuffer该如何选择?

效率是否可变是否安全
String×
StringBuffer
StringBuilderX

1.StringBuffer是线程安全的,因为他的方法是采用synchornized(同步锁机制)修饰,因此是安全的,但是他是可变的。
2.StringBuilder是线程不安全的,没有同步锁机制。但是是可变的。

  • 当使用少量数据时可以使用String类,因为如果大量数据使用+号连接字符串,那么会底层频繁的创建StringBuilder对象,导致内存开销大。
  • 当使用大量数据时,不需要考虑线程安全的问题时,那么可以使用StringBuilder对象,通过append方法追加。
  • 当使用大量数据时并且考虑多线程环境时,那么需要使用StringBuffer对象,也可以使用StringBuilder对象,但是需要我们自己加锁机制保证多线程环境下安全。

7.StringPool是什么?

JVM为了提升性能和减少内存开销,避免字符串的重复创建,维护了一块特殊的内存空间,即字符串常量池(StringPool),它保存着所有字符串字面量,这些字面量在编译时期就确定,还可以使用String的intern()方法在运行过程中将字符串添加到池中。

当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。


注:final的用法? 修饰类、属性、方法。

  1. final可以修饰类,表示该类不能被继承。所以该类没有子类
  2. final可以修饰属性,
    1. 修饰普通成员变量,则表示常量,必须直接初始化或者构造函数初始化或者代码块初始化
    2. 修饰静态成员变量,则表示常量,必须直接初始化或者静态代码快初始化
    3. 修饰形式参数,则表示在该作用域内只允许读、不允许修改
  3. final可以修饰方法,则表示该方法在类被继承后不能被重写。
  4. final修饰的引用类型变量时,该变量不允许指向其他。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值