Java 中字符串的支持是通过在 JDK 中提供一个名为 String 的类,对应字符串这个变量类型

String 类的特点

  • String 类的底层使用 char 的数组保存数据
  • String 类是一个 final 类,不允许被继承
  • String 类是一个 immutable 类,该类的对象生成后,内容不会发生变化。该类中的所有返回 String 类型对象的成员方法都是返回一个新的 String 对象
  • 方法区中有一块区域名为“常量区”, 用于存储编译时和运行时的字符串常量

String 类方法

String 类作为对应字符串的类,该类中含有大量的方法用来完成字符串相关的构造、裁剪、拼接与替换等功能,大部分为方法重载

创建对象的两种方式

Java 中的字符串对象比较特殊,比普通 Java 类有多一种创建对象的方法,即“字符序列法”

1
2
String strA = "WiHieree";
String strB = new String("WiHieree");

以上两种方式创建的对象区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class StringTest {
public static void main(String[] args) {
String strA = "Wihieree";
String strB = "Wihieree";
System.out.println(strA == strB);
System.out.println(strA.equals(strB));

String strC = new String("Wiyee");
String strD = new String("Wiyee");
System.out.println(strC == strD);
System.out.println(strC.equals(strD));
}
}

//输出结果
true
true
false
true

机制在于JVM内存模型的方法区中有一个 String 常量池(方法去内存),对于使用字符序列方式创建对象,JVM首先会查看字符串常量池中是否已经存在该对象,如果存在,则直接已存在对象而不会新建对象;对于使用 new 运算符方式创建对象,JVM会直接在堆中分配一个新的String对象,如下图所示:
代码片段的内存布局见图

字符串的比较(equals 与 ==)

  • 对于 ==,如果作用与基本数据类型(byte、short、char、int、long、float、double、boolean)的变量,则比较的是其存储的“值”是否相等;如果作用与引用类型的变量,则比较其所指向的对象的地址是否相同(即是否同一个对象)。在 Java 中,String 是引用类型
  • String的 equals 方法继承自 Java 中的超级父类 Object,Object 的 equals 方法用来比较两个对象的引用是否相等(即是否同一个对象)。但是,String 的 equals 方法不仅是简单地继承,而是进行了重写(Override),用来比较两个 String 对象所存储的字符序列值是否相等

intren 方法

1
2
3
4
5
6
7
8
9
10
11
12
public class StringTest {
public static void main(String[] args) {
String strA = "WiHieree";
String strB = new String("WiHieree");
System.out.println(strA.intern().equals(strB.intern()));
System.out.println(strA.intern() == strB.intern());
}
}

//输出结果
true
true

无论是字符串常量区中的 String 对象,还是堆内存中的 String 对象,它们的 intern 方法都是去 JVM 中的字符串常量区获取相等字符序列的 String 对象返回

值传递/引用传递

Java 中只有值传递机制,而没有引用传递机制,所以 String 参数是值传递方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class StringTest {
public static void main(String[] args) {
String arg = new String("WiHieree");
change(arg);
System.out.println("main arg ---> " + arg);
}

private static void change(String arg) {
arg = "Wiyee";
System.out.println("chang arg ---> " + arg);
}
}

//输出结果
chang arg ---> Wiyee
main arg ---> WiHieree

字符串与数组之间的转换

字符串不是数组,但是字符串可以转换成数组,反之亦然

1
2
3
字符 ----> 数组         toCharArray         char[] chars = "WiHieree".toCharArray();
数组 ----> 字符 String str = new String(new char[]{'W','i','y','e','e'});
String str = String.valueOf(new char[]{'W','i','y','e','e'});

String、StringBuffer 和 StringBuilder 的区别

对象的可变与不可变

StringBuffer/StringBuilder 类是可以替代 String 类的另一种处理字符串的解决方案,比 String 类更灵活
可以给一个 StringBuilder或StringBuffer 中添加、插入或追加新的内容,但是 String 对象一旦创建,它的值就确定了

效率(使用 StringBuffer 连接字符串)

除了 StringBuffer 中修改缓冲区的方法是同步的之外,StringBuilder 类与 StringBuffer 类是很相似的
如果是多任务并发访问,就使用 StringBuffer ;而如果是单任务访问,使用 StringBuilder 会更有效

1
2
3
+StringBuilder()                        构建一个容量为 16 的空的字符串生成器
+StringBuilder(capacity: int) 构建一个指定容量的字符串生成器
+StringBuilder(s: String) 构建一个带指定字符串的字符串生成器

eg. +append(data: char[]): StringBuilder 将字符串和字符追加到字符串生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StringTest {
public static void main(String[] args) {
StringBuilder a = new StringBuilder();
a.append("Welcome");
a.append(" ");
a.append("to");
a.append(" ");
a.append("WiyeeLu's blog");
System.out.println(a);
}
}

//输出结果
Welcome to WiyeeLu's blog


 Comments