Java中String类型的创建关系、什么是常量池、以及StringBuilder/Buffer等
Java的String字符串使用
String s1 = "Hello World";
String s2 = "Hello World";
String s3 = new String("Hello World");
String s4 = new String("Hello World");
System.out.println(s1==s2); // true
System.out.println(s1==s3); // false
System.out.println(s3==s4); // false
这段 Java 代码中,字符串 s1 和 s2 都使用字面量的方式赋值,它们在编译时会被放入常量池中。由于字符串常量池的特性,s1 和 s2 在常量池中的引用地址是相同的,因此 s1 == s2 的结果为 true。
而字符串 s3 和 s4 是通过 new 关键字创建的,它们在内存中是两个不同的对象,因此 s3 == s4 的结果为 false。
需要注意的是,字符串比较应该使用 equals() 方法,而不是 == 操作符。在上述代码中,使用:
System.out.println(s1/s2/s3/s4.equals(s1/s2/s3/s4));
输出结果都出结果都是true。
扩充知识1:什么是常量池
Java 常量池(Constant Pool)是 Java 虚拟机在执行程序时所维护的一块内存区域,它用于存放在编译期被确定,并被保存在 class 文件中的各种常量、符号引用和字面量等。
常量池中包含了以下类型的常量:
字面量:包括字符串、数字和布尔型常量。
符号引用:包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等。
运行时常量:包括动态生成的字符串和类名等。
在 Java 中,字符串常量池和类常量池是两种常量池,分别用于存放字符串常量和类常量。字符串常量池用于存放字符串字面量,类常量池用于存放类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等。
由于 Java 常量池的特性,相同的字符串字面量在常量池中只会被存储一次,因此多个引用变量可以共享同一个字符串字面量,从而减少了内存的占用。例如:
String s1 = "Hello World";
String s2 = "Hello World";
System.out.println(s1 == s2); // true
在这个例子中,字符串 “Hello World” 只会被存储一次,s1 和 s2 都引用同一个字符串字面量,因此 s1 == s2 的结果为 true。
需要注意的是,通过 new 关键字创建的字符串对象不会被放入常量池中,每次创建都会生成一个新的对象。例如:
String s3 = new String("Hello World");
String s4 = new String("Hello World");
System.out.println(s3 == s4); // false
在这个例子中,字符串 s3 和 s4 是通过 new 关键字创建的,它们在内存中是两个不同的对象,因此 s3 == s4 的结果为 false。
扩充知识2:String | StringBuilder | StringBuffer
String、StringBuilder 和 StringBuffer 都是 Java 中用于处理字符串的类,它们有以下的区别:
- String 类型是不可变的,一旦创建就不能修改。而 StringBuilder 和 StringBuffer 类型都是可变的,可以随时修改其值。
- 在字符串拼接时,如果使用 String 类型进行拼接,会导致创建大量的中间字符串对象,这会占用大量的内存和系统资源。而 StringBuilder 和 StringBuffer 类型则不会创建中间对象,可以直接对字符串进行修改,因此在频繁的字符串拼接操作中,StringBuilder 和 StringBuffer 的效率更高。
- StringBuilder 是线程不安全的,而 StringBuffer 是线程安全的。在多线程环境下,使用 StringBuffer 类型可以避免竞争条件的发生,但是会带来一定的性能开销。
- StringBuilder 和 StringBuffer 的 API 是类似的,但是 StringBuffer 中的方法都是 synchronized 关键字修饰的,因此在使用 StringBuffer 时需要考虑到同步的问题。而 StringBuilder 则没有这个问题。
因此,如果不需要考虑多线程的安全问题,可以使用 StringBuilder 类型来进行字符串的拼接和修改。如果需要考虑多线程的安全问题,则应该使用 StringBuffer 类型。如果只是进行字符串的读取和操作,可以使用 String 类型。