String StringBuild StringBuffer


参考链接: 探秘Java中的String StringBuild StringBuffer

1.String

  • String:是不可变对象,对象的任何改变都不影响到原对象,即对象一旦生成,就不能被更改。对String对象的改变会引发新的String对象的生成。
  String str = "hello" ;
  str = str + " world" ;
  str += "!!!" ;
  System.out.println(str); //hello word!!!

分析代码:生成了一个新的String对象。然后让引用指向新的String对象。所以内容经常改变的字符串不要使用String类型,由于这样会造成内存中大量的无引用对象,然后JVM的GC就会开始工作。
在这里插入图片描述

1.1为什么要把String设计成不可变的?

String str1 = "hehe";   String str2 = "hehe";
//假设字符串是可变对象,通过 str1 修改了 ”hehe“ 之后,会影响到 str2 
  1. 为了避免相互影响,把 String 设计成不可变的。
  2. 不可变对象是线程安全的。
  3. 不可变对象的 hash code 也是不变的, 作为 key 时可以更高效的保存到 HashMap 中。

不可变很大程度是为了实现“常量池”

1.2为什么说String是不可变的?

String类被 final 修饰,是不可以被继承,方法不可以被重写的;底层是由final修饰的 char[] 组成的,说明该数组的引用地址不是可以发生改变的。并且并没有提供该数组的 get , set 操作,char 数组内的数据因此也不可以被改变。所以说 String 是不可变的。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence
{
    /** The value is used for character storage. */
    private final char value[];
 
    /** The offset is the first index of the storage that is used. */
    private final int offset;
 
    /** The count is the number of characters in the String. */
    private final int count;
 
    /** Cache the hash code for the string */
    private int hash; // Default to 0
 
    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
 
    ......
    
}

注意:通过反射可以改变。

补充:通过反射修改字符串

反射是通过

  • 反射是面向对象编程的一种重要特性, 有些编程语言也称为 “自省”。
  • 指的是程序运行过程中, 获取/修改某个对象的详细信息(类型信息, 属性信息等), 相当于让一个对象更好的 “认清自己”。
 /*
String.class
类比喻成一张图纸,对象则就是盖出来的房子,房子消耗空间,图纸本身也对应着一个“类对象”。
每个类都有一个自己对应的类对象。
*/

String str = "hello";
// 获取 String 类中的 value 字段. 这个 value 和 String 源码中的 value 是匹配的.
// 源码中 private final char value[]
Field valueField = String.class.getDeclaredField("value");
// 将这个字段的访问属性设为 true
valueField.setAccessible(true);
// 把 str 中的 value 属性获取到.
char[] value = (char[]) valueField.get(str);
// 修改 value 的值
value[0] = 'h';
System.out.println(str); 

//执行结果 
hello

1.3String类中两种对象实例化的区别

  1. 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
  2. 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中,可以使用intern()方法手工入池。

1.4 解释字符串 += 操作

每次执行 += 操作,都会构造一个新的长字符串,比较低效。在代码中尽量少 +=操作。

String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);

// 执行结果
hello world!!!
// 不是 String 对象本身发生改变, 而是 str 引用到了其他的对象

在这里插入图片描述

1.5字符串常量池

String类的设计使用了共享设计模式

理解“池”(pool),它是计算机中的一个重要术语,目的是为了提高程序效率

在JVM底层实际上会自动维护一个对象池(字符串常量池):

  • 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中。
  • 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用。
  • 如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用。
   public static void main(String[] args) {
        String str1 = "hehe";
        String str2 = "hehe";
        String str3 = new String("hehe");

        //   ==   判断地址是否一致
        // equals 判断内容是否相同
        // 对于内容相同的字符串常量,在内存中没有必要存两份,只需要存一份即可
        // JVM 中是通过“字符串常量池”方式来实现的
        System.out.println(str1 == str2);// true
        System.out.println(str1.equals(str2));// true
        System.out.println(str1 == str3); // false
        System.out.println(str1.equals(str3)); // true
    }

2.StringBuffer

  • StrinhBuffer:每次都对对象本身进行操作,而不是生成新的对象。所以在字符串内容不断改变的情况,建议使用StringBuffer。
  • StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的类。
  • String对象的字符串拼接其实是被JVM解释成了StringBuffer对象的拼接,所以这些时候String对象的速度并不会比StringBuffer慢。

例如:如下代码,String的效率远比StringBuffer快。

  String string = “I am a” + “ little” + “ girl.; 
  StringBuffer stringBuffer = new StringBuilder(“I am a”).append(“ little”).append(“ girl.); 

解释:在JVM眼里:String srting = “I am a” + “ little” + “ girl.”;就是String stringBuffer = “I am a little girl.”;

3.StringBuild

  • StringBuild 是 JDK1.5 新增加的一个类,与 StringBuffer 具有相同的操作(方法和功能完全是等价)。
  • StringBuild 是线程不安全的 类。
  • 单线程程序下,StringBuild 效率更快,因为它不需要加锁;而 StringBuffer 则每次都需要判断锁,效率相对更低。

三者适用场景

String:适用于少量的字符串操作的情况,即创建复制后,修改的比较少的情况。

StringBuffer:适用于多线程下字符串缓冲区进行大量操作的情况。

StringBuilder:适用于单线程下字符串缓冲区进行大量操作的情况。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值