一、理解String类

1、String类简介

String类是Java中用于处理字符串的类,其基本特点是具有不可变性。

2、String对象的内存区域

声明一个String对象的2种方式:

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

第1种方式 :首先会在JVM的常量池中查找是否已经存在“hello”这个字符串常量,如果存在,则直接将其引用返回,并赋值给s1;如果不存在,则在常量池中新创建一个“hello”的字符串常量,并将其引用返回赋值给s1。

第2种方式:无论方法区中是否有“world”字符串常量,都会在JVM的堆内存中重新创建一个新的String对象,并将其引用返回。

因此,以下程序有如下结果:

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

System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s3 == s4); // false

String的intern方法:

两个字符串s、t,当且仅当s.equals(t)时,s.intern() == t.intern()。

3、String的不可变性及其原理

String对象的一个重要特点就是其不可变性,Java中其他具有不可变性的类还有Integer等基本类型的包装类。这里的不可变,不是指向String对象的引用不可变,而是String对象内部中存储的字符串的值不可变。如下,String类的引用s1先是指向的“hello”这个字符串对象,然后被修改为指向了“world”这个字符串对象。

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

如下图所示:

下面从源码分析String对象不可变的原理,String类的不可变主要是从以下2个方面保证的:

1、String类被final修饰,保证其不能被其他类继承,避免子类修改String类中的属性;

2、String对象中,用于存储字符串的实际上是一个名为value的char类型的数组。如下,该数组被private和final修饰。首先,被final修饰,说明String对象被初始化之后,value这个引用不能被修改指向其他数组,即使是通过反射也不行。其次,被private修饰,表明value数组这个属性只能在当前类里面被访问,且未对外提供setter方法,所以其他类不能直接访问value数组,也就没有办法修改value数组中元素的值。

public final class String
        implements java.io.Serializable, Comparable<java.lang.String>, CharSequence {
    ...
    
    private final char value[];

    ...

}

4、String、StringBuilder、StringBuffer的区别

为了保证安全,String类被设计为不可变的。但是在某些情况,需要频繁的对字符串进行拼接修改,如果采用String类,就会导致较大的开销。为了解决这个问题,StringBuffer和StringBuilder就应运而生。StringBuilder和StringBuffer是可变的,即其中存储的字符串可以改变,而不用创建的新的对象。两者的区别在于:

StringBuilder是线程不安全的,当多个线程并发修改时,可能出现不一致的情况。

StringBuffer是线程安全的,在多个线程并发修改时,依然能够保证一致性。但是,由于锁的开销,因此,StringBuffer的性能略低于StringBuilder。

综上:当字符串的值不会经常变化时,用String类比较合适;如果字符串的值会频繁变化,单线程下推荐使用StringBuilder,多线程下使用StringBuffer。

参考:

深入理解Java String类【作者:PesenX】

おすすめ

転載: blog.csdn.net/sun_lm/article/details/86591207