String 类

String 字符串特性

  1. final 类,不可被继承
  2. 实现 Serializable 接口,支持序列化
  3. 实现 Comparable 接口,可比较大小
  4. 内部使用 final char 数组存储字符串数据,解释类 String 不可更改原因
  5. String 具有不变性,体现:
    1. 字面量赋值,字符串值存储在字符串常量池中(常量池不会存储相同内容字符串)
    2. 对字符串进行修改(replace)或者是拼接(StringBuilder、StringBuffer、直接+)字符串时,不会修改原值,而是新建一个值,在新值上修改或拼接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String[] args) {
//字符串定义方式
String s1="abc";
String s2="abc";
System.out.println(s1==s2);
System.out.println("________________");
//字符串拼接不会修改原字符串值,会新建一个原值并修改
String s3="abc";
s3+="hello";
System.out.println(s3==s1);
System.out.println("________________");
//字符串修改同拼接不会修改原值,会新建一个原值并修改
String s4="abc";
s4.replace("a","m");
System.out.println(s4);
System.out.println(s4==s1);
System.out.println("________________");

}

String 字面量赋值和构造器赋值区别


使用构造器的变量指向的地址是堆中的地址,堆再指向 abc

字面量变量地址指向的是 abc

字符串常量池中不会存在两个相同的字符串

String 和基本数据类型、包装类之间转换

String 转包装类、基本数据类型

调用对应包装类的 parseXxx(Str)方法

包装类、基本数据类型转 String

调用 String 类的 valueOf();

面试题:

构造器创建的字符串在内存中创建了几个对象?

最多两个,如果字符串常量池中存在该字符串,则只在堆中创建一个空间,存放字符串常量池中对应字符串的地址!!!

String 陷阱

String s1 = “a”;

说明:在字符串常量池中创建了一个字面量为“a”的字符串。

s1 = s1 + “b”;

说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符

s1+”b”(也就是“ab”)。如果多次执行这些改变串内容的操作,会导致大量副本

字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响

程序的性能。

String s2 = “ab”;

说明:直接在字符串常量池中创建一个字面量为”ab”的字符串。 String s3 = “a” + “b”;

说明:s3指向字符串常量池中已经创建的“ab”的字符串。

String s4 = s1.intern();

说明:堆空间的s1对象在调用intern()之后,会将常量池中已经存在的“ab”字符串

赋值给 s4。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
String  s9="hello";
String s10="world";
String s11="hello"+"world";

String s12=s9+"world";
String s13="hello"+s10;
String s14=s9+s10;
String s15="helloworld";
//true
System.out.println(s15==s11);
//false
System.out.println(s12==s11);
//false
System.out.println(s13==s11);
//false
System.out.println(s14==s11);
//false
System.out.println(s12==s14);
String s16=s14.intern();
System.out.println(s11==s16);

总结:

  1. 常量与常量的拼接修改结果存在常量池中,且不会存在相同内容的常量
  2. 只要是变量的拼接或修改,地址为堆中的地址。
  3. 调用 intern 返回的是常量池中存在的地址

StringBuffer 和 StringBuilder 类

三者异同点

String:不可变字符串序列
StringBuffer:线程安全,效率低,可变字符串序列
StringBuilder:线程不安全,效率高,可变字符串序列 jdk5 新增
原因:append 方法是否被 synchronized 修饰

源码分析

StringBuffer sb1=new StringBuffer();//底层创建一个长度为 16 的 char 数组
sb1.append(‘a’);//value[0]=a;
sb1.length()//等于数组实际存储的字符数,不等于数组长度

扩容流程

  1. 调用 append 方法,
  2. 调用父类的 append 方法
  3. 调用 ensureCapacityInternal,确保数组长度够用
  4. 如果不够用进行数组长度*2+2,再调用 arraysCopy 的方法将原有数组复制到新数组中