一句话概括
String 在 Java 中是一个表示文本的数据类型,但它不是像 int 或 double 那样的基本数据类型,而是一个类。

详细解释
String 是什么?
String 是 Java 中用来表示一串字符("Hello, World!")的类,当你想在程序中处理任何文本信息时,比如用户名、密码、消息、文件路径等,你都会用到 String。
示例:
String name = "张三"; // 创建一个 String 对象,存储名字 "张三" String message = "你好,Java!"; // 创建一个 String 对象,存储消息 System.out.println(name); System.out.println(message);
String 的核心特点(非常重要)
理解 String 的以下几个特点,是掌握它的关键:
a) 不可变性
这是 String 最重要的一个特性,一旦一个 String 对象被创建,它的内容就不能被修改。

如何理解“不可变”?
- 不是不能重新赋值:你可以让一个
String变量引用一个新的字符串,但这不代表原来的字符串被修改了。 - 底层原理:
String内部的字符数组被final修饰,并且没有提供任何可以修改这个数组内容的方法。
举个例子:
String str1 = "hello"; // 看似修改了 str1,但实际上发生了以下事情: // 1. JVM 在内存中创建了一个新的字符串 "hello world"。 // 2. 变量 str1 不再指向原来的 "hello",而是指向了这个新的 "hello world"。 // 3. 原来的 "hello" 对象如果没有被其他变量引用,就可能被垃圾回收器回收。 str1 = str1 + " world"; System.out.println(str1); // 输出: hello world
为什么 String 要设计成不可变?
- 安全性:在多线程环境下,如果字符串可以被修改,一个线程修改了字符串的内容,可能会导致其他依赖该字符串的线程出现问题,不可变性保证了线程安全。
- 性能优化:因为
String不可变,JVM 可以对它进行一些优化,对于"a" + "b"这样的操作,编译器会直接优化成"ab",而不是创建两个临时对象,更重要的是,Java 使用了一个叫做 字符串常量池 的机制,当你创建一个字符串字面量(如String s = "abc")时,JVM 会先在常量池中查找是否存在"abc",如果存在就直接引用,不存在才创建新的,这大大节省了内存。
b) String 对象的创建方式
有两种主要的创建方式,它们的内存行为不同:

-
字面量赋值(推荐)
String str = "hello";
这种方式创建的字符串,会首先被放入字符串常量池,如果池中已有相同内容的字符串,则直接引用,不会创建新对象。
-
使用
new关键字String str = new String("hello");这种方式一定会在堆内存中创建一个新的
String对象,即使常量池中已经存在"hello",它会先检查常量池,如果有"hello",就直接用,然后在堆里再创建一个一模一样的对象。
对比:
// 方式一
String s1 = "hello";
String s2 = "hello";
// s1 和 s2 指向常量池中的同一个 "hello" 对象
System.out.println(s1 == s2); // 输出 true (== 比较的是内存地址)
// 方式二
String s3 = new String("hello");
String s4 = new String("hello");
// s3 和 s4 都是在堆中创建的新对象,地址不同
System.out.println(s3 == s4); // 输出 false
// s1 和 s3 一个在常量池,一个在堆,地址也不同
System.out.println(s1 == s3); // 输出 false
注意: 比较的是两个对象的内存地址(是否是同一个对象),而 String 类重写了 equals() 方法,equals() 比较的是两个字符串的内容是否相同。
System.out.println(s3.equals(s4)); // 输出 true (比较内容)
c) 常用方法
String 类提供了非常丰富的方法来操作字符串:
-
获取信息
length(): 获取字符串长度。charAt(int index): 获取指定索引位置的字符。indexOf(String str): 查找子字符串第一次出现的位置。
-
转换
toUpperCase()/toLowerCase(): 转换为大写/小写。trim(): 去除字符串两端的空格。split(String regex): 根据正则表达式分割字符串。substring(int beginIndex, int endIndex): 截取子字符串。
-
判断
equals(Object anObject): 比较内容是否相等。equalsIgnoreCase(String anotherString): 忽略大小写比较内容。startsWith(String prefix) / endsWith(String suffix): 判断是否以指定字符串开头/contains(CharSequence s): 判断是否包含指定子序列。
-
连接
- 运算符:最简单直观的连接方式,编译器会优化成
StringBuilder的append()方法。 concat(String str): 连接两个字符串。
- 运算符:最简单直观的连接方式,编译器会优化成
示例:
String text = " Hello Java ";
System.out.println("原始字符串: '" + text + "'");
System.out.println("长度: " + text.length()); // 输出: 13
System.out.println("去除空格后: '" + text.trim() + "'"); // 输出: 'Hello Java'
System.out.println("转换为大写: " + text.toUpperCase()); // 输出: HELLO JAVA
System.out.println("是否包含 'Java': " + text.contains("Java")); // 输出: true
| 特性 | 描述 |
|---|---|
| 本质 | 一个 final 类,用于表示文本。 |
| 核心特点 | 不可变性:创建后内容不能被修改,任何修改操作都会创建新的 String 对象。 |
| 创建方式 | 字面量 (String s = "abc"):存于字符串常量池,节省内存。new 关键字 (String s = new String("abc")):存于堆内存,一定会创建新对象。 |
| 比较 | 比较内存地址(是否是同一个对象)。equals() 比较字符串内容(是否相同)。 |
| 用途 | 处理所有文本相关的数据,如用户输入、文件路径、消息等。 |
| 性能 | 由于不可变性,适合在多线程环境下使用,并且字符串常量池带来了内存和性能上的优势。 |
String Java 用来处理文本的工具箱,它的“不可变”是其设计的基石,带来了安全、高效和易于管理的优点。
