在Java编程中,字符串(String)是最常用的数据类型之一。作为Java核心类库中的基础类,String类承载着处理文本数据的重要使命。本文将深入探讨Java中String类的核心特性,包括其不可变性、创建方式、内存模型以及字符串比较方法。
1. 一、String类的基本概述
java.lang.String类代表字符串,Java程序中的所有字符串文字(例如"abc")都为此类对象。字符串的内容是不可变的,一旦创建后,其内容就不能被修改。这是String类最重要的特性之一,也是理解Java字符串行为的关键。
ini
String str = "Hello";
str = "World"; // 这不是修改原字符串,而是创建了新字符串对象
二、创建String对象的两种方式
1. 直接赋值
ini
String name = "Jack";
这种方式会直接在字符串常量池(String Pool)中查找是否存在相同的字符串,如果存在则直接引用,不存在则创建新字符串并放入池中。
2. 使用new构造方法
| 构造方法 | 说明 |
|---|---|
| public String() | 创建空白字符串,不含任何内容 |
| public String(String original) | 根据传入的字符串,创建字符串对象 |
| public String(char[] chs) | 根据字符数组,创建字符串对象 |
| public String(byte[] chs) | 根据字节数组,创建字符串对象 |
javascript
String s2 = new String(); // 创建空白字符串
String s3 = new String("abc"); // 根据传入字符串创建
String s4 = new String(new char[]{'a', 'b', 'c'}); // 根据字符数组创建
String s5 = new String(new byte[]{97, 98, 99}); // 根据字节数组创建
注意 :使用new创建的字符串对象,无论内容是否相同,都会在堆内存中创建新的对象,不会去字符串常量池中查找。
arduino
public class StringDemo1 {
public static void main(String[] args) {
//1.使用直接赋值的方式获取一个字符串对象
String s1 = "abc";
System.out.println(s1);
//2.使用new的方式来获取一个字符串对象
String s2 = new String();
System.out.println("@"+s2+"!");
//传递一个字符串,根据传递的字符串内容再创建一个新的字符串对象
String s3 = new String("abc");
System.out.println(s3);
//传递一个字符数组,根据字符数组的内容再创建一个新的字符串对象
//需求:我要修改字符串的内容。 abc Qbc
//abc --> {'a','b','c'} --> {'Q','b','c'} --> "QBC"
char[] chs = {'a','b','c','d'};
String s4 = new String(chs);
System.out.println(s4);
//传递一个字节数组,根据字节数组的内容再创建一个新的字符串对象
//应用场景,以后在网络中传输的数据其实都是字节信息
//我们一般要把字节信息进行转换,转成字符串,此时就要用到这个构造了。
byte[] bytes = {97,98,99,100};
String s5 = new String(bytes);
System.out.println(s5);;
}
}
三、String的内存模型
1. 串池(StringTable)
在JDK 7之前,串池位于方法区中;从JDK 7开始,串池被移动到了堆内存中。这一变化使得字符串管理更加灵活,也减少了内存溢出的风险。

2. 直接赋值与串池
当使用双引号直接赋值时,系统会检查串池中是否存在相同内容的字符串:
- 不存在:创建新字符串并放入串池
- 存在:直接引用串池中的字符串
ini
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); // 输出 true,因为s1和s2引用的是同一个字符串常量
3. new创建与堆内存
使用new创建的字符串对象,无论内容是否相同,都会在堆内存中创建新对象:
ini
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s3 == s4); // 输出 false,因为s3和s4是两个不同的对象
四、字符串的比较
1. ==号比较
- 基本数据类型:比较的是数据值
- 引用数据类型:比较的是地址值(即对象在内存中的位置)
ini
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); // 输出 false,因为s1在堆中,s2在常量池中
2. equals()方法
equals()方法用于比较字符串的内容是否相等,区分大小写:
ini
boolean result = s1.equals(s2); // true,因为内容相同
3. equalsIgnoreCase()方法
equalsIgnoreCase()方法用于比较字符串内容是否相等,忽略大小写:
ini
String s1 = new String("Abc");
String s2 = "abc";
System.out.println(s1.equals(s2)); // false,区分大小写
System.out.println(s1.equalsIgnoreCase(s2)); // true,忽略大小写
五、实际应用示例
typescript
public class StringDemo {
public static void main(String[] args) {
// 1. 直接赋值
String s1 = "Hello";
String s2 = "Hello";
// 2. 使用new创建
String s3 = new String("Hello");
String s4 = new String("Hello");
// 3. 比较
System.out.println("s1 == s2: " + (s1 == s2)); // true
System.out.println("s1 == s3: " + (s1 == s3)); // false
System.out.println("s1.equals(s3): " + s1.equals(s3)); // true
System.out.println("s1.equalsIgnoreCase(s4): " + s1.equalsIgnoreCase(s4)); // true
}
}
六、总结
- String不可变性:字符串一旦创建,其内容不能被修改,这是Java字符串设计的核心原则。
- 字符串创建 :有两种主要方式------直接赋值(使用字符串常量池)和
new构造(在堆中创建新对象)。 - 内存模型:JDK 7后,字符串常量池从方法区移动到堆内存,这一变化影响了字符串的存储和管理。
- 字符串比较 :
==比较的是对象地址,equals()比较的是内容(区分大小写),equalsIgnoreCase()比较内容且忽略大小写。
理解这些特性对于编写高效、安全的Java代码至关重要。在实际开发中,应根据需求选择合适的字符串创建和比较方式,避免不必要的内存浪费和逻辑错误。
小贴士 :在需要频繁拼接字符串的场景中,应使用StringBuilder或StringBuffer,因为String的不可变性会导致大量临时对象的创建,影响性能。
通过深入理解Java中String类的工作原理,我们可以更好地利用这一基础类库,编写出更加高效、健壮的Java应用程序。