Java String类笔记

声明

文章均为本人技术笔记,转载请注明出处https://segmentfault.com/u/yzwall


String的不可变性

String的不可变性

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

public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}
  • String类字符串存储方式:值使用final char value[]类型的字符数组存储,因此一旦赋值不可改变;

    • String类存储字符串,使用Array.copyof方法value[]赋值,并开辟内存空间;

  • String类不可继承:使用final修饰符,表示String类不可继承;

  • String类提供的所有方法中,有返回String的一律新建一个String对象,防止对原String对象进行修改;

String对象创建

字符串常量池:位于常量池中,由String类私有维护,池中元素都是String对象,每个String对象的字面值是唯一的,由GC回收;
String常量对象创建场合:当String对象第一次常量赋值和调用String对象调用intern()方法时,常量池中创建对应String常量对象;

String str1 = "abc";
String str2 = "abc";
String str3 = str1;
String str4 = new String("abcd");
String str5 = new String("abc");

String对象创建,分为直接常量赋值与new运算符创建,创建String新对象时创建1个或2个String对象;

直接字符串常量赋值

创建对象时,在编译阶段,编译器先去字符串常量池检查是否有String常量对象拥有字面值"abc",

  • 存在/str2:在栈中创建引用,指向常量池中的Strng常量对象(字面值为"abc");

  • 不存在/str1:在常量池中创建匿名Strng对象(字面值为"abc"),在栈中创建引用,指向String常量对象;

使用new运算符创建

创建对象时,程序先去字符串常量池检查是否有String对象拥有字面值"abc",

  • 存在/str5:在栈中创建对象引用,在堆区为实例分配内存,但是字符数组value字段保存常量对象(常量池中)的value字段的引用;

  • 不存在/str4:在栈中创建对象引用,在堆区为实例分配内存,在常量池中创建String常量对象,字符数组value字段保存常量对象(常量池中)的value字段的引用;

String类的intern()方法
String str6 = new String("abc");
String a = str6.intern();
String str7 = "xyz";
String b = str7.intern();

str.intern()首先检查常量池中的String常量对象字面值是否有与str.value相等的,若有直接返回对应String常量对象的引用,否则在常量池中创建字面值为str.value的String常量对象并返回引用;

String类判等:equals方法和等号运算符:

String str1 = "abc";
String str2 = str1;
String str3 = new String("abc");
String str4 = str3;
String str5 = new String("abc");

// String equals只用于判断字面值是否相同,以下结果均为true
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str3.equals(str4));
System.out.println(str3.equals(str5));

// false,str1与str3引用不同对象
System.out.println(str1 == str3);
// false,str3与str5引用不同对象
System.out.println(str3 == str5;
  • equals()方法检测两个字符串变量/常量是否相等;

  • ==运算符判断两个String对象的引用地址是否相同,即判断引用变量引用指向同一个对象;

String:空串与null

  1. 空串""是长度为0的字符串,用if(str.length() == 0)if(str.equals(""))判断;

  2. null表示String对象为空,用if(str == null)判断;

String、StringBuilder,StringBuffer辨析

三者可变性与线程安全辨析

  • String类由于对象不可变,线程安全 【异】

  • StringBuilder与StringBuffer都继承AbstractStringBuilder类,字面值char[] value均可变【同】

  • StringBuffer中主要方法用synchronized加了同步锁,因此线程安全【异】

  • StringBuilder方法没有加同步锁,因此线程不安全,但在非多线程场景下,效率高于StringBuilder【异】

三者适用场景【异】:

  • 使用String类:适用于字符串不频繁变化的场景,比如常量生命,少量变量运算;

  • 使用StringBuilder类:适用于单线程环境下字符串频繁变化的场景;

  • 使用StringBuffer类:适用于多线程环境下字符串频繁变化的场景;

  • String类重写了equals()方法和hashCode()方法,StringBuilder和StrngBuffer没有,因此将后两者对象存储Java集合类中会出现问题;

String对象"+/+="本质

  • 在进行连接操作(“+”和 “+=”)时,String每次返回一个新的String实例,而StringBuffer/StringBuilder的append()直接返回this;

  • String类“+”和 “+=”操作符是Java中唯一重载的两个操作符。这两个操作符都是编译器默认引入了StringBuilder类,最后都调用toString()方法返回String对象,StringBuilder临时对象被GC回收,因此效率极为低下;


yzwall
120 声望17 粉丝

对大规模分布式系统技术兴趣浓厚