一、final 关键字
前置知识:Java 数据类型分类
- 基本数据类型:byte/short/int/long/float/double/char/boolean,直接存储数据值
- 引用数据类型:类、接口、数组、字符串等,存储的是对象的内存地址
1. final 修饰变量(常量)
核心规则
- 基本数据类型:赋值后值不可修改
- 引用数据类型:引用地址不可修改,但对象内部内容可修改
- 赋值规则:
- 成员变量:声明时赋值 / 构造方法赋值 / 代码块赋值(三选一)
- 局部变量:可先声明,使用前赋值即可
public class FinalDemo { // 1. final修饰成员变量(基本数据类型) private final int NUM = 10; // 2. final修饰引用数据类型(数组) private final int[] ARR = {1,2,3}; public void test() { // 基本数据类型常量:无法修改值 // NUM = 20; 编译报错 // 引用类型:地址不能改,内部元素可以改 // ARR = new int[5]; 编译报错 ARR[0] = 100; // 正常运行 // final修饰局部变量:使用前赋值即可 final String NAME; NAME = "Java"; // NAME = "Python"; 编译报错 } }
2. final 修饰方法
- 特性:不能被子类重写,但可以被继承和调用
- 作用:保护核心业务逻辑,防止子类篡改
class Parent { // final方法:禁止重写 public final void work() { System.out.println("核心工作逻辑"); } } class Child extends Parent { // 编译报错:无法重写final方法 // public void work() {} }
3. final 修饰类
- 特性:不能被继承,没有子类
- 典型案例:
String、StringBuffer、Integer等包装类
final class FinalClass {} // 编译报错:无法继承final类 // class SubClass extends FinalClass {}
二、String 类
1. 底层数据结构演进
| JDK 版本 | 底层存储结构 | 优势 |
|---|
| 1.8 及以前 | private final char value[] | 兼容所有字符 |
| 1.9 及以后 | private final byte value[] | 节省内存,提升性能 |
2. String 不可变性的双重保障
- 类被 final 修饰:杜绝继承,防止通过子类破坏不可变性
- 底层数组被 private + final 修饰:
final:数组地址不可变private:外部无法直接访问修改数组元素
3. 不可变性的核心优势
- 线程安全:多线程环境下无需加锁,直接使用
- 字符串常量池复用:相同内容的字符串只存一份,节约内存
三、字符串拼接与可变字符串类
1. String 拼接的缺陷
- String 不可变,每次
+=拼接都会创建新的 String 对象,效率极低 - 编译期优化:纯字面量拼接会直接合并,不创建多余对象
// 编译期优化:直接生成 "ab",无中间对象 String s1 = "a" + "b"; // 变量拼接:会创建新对象,效率低 String a = "a"; String b = "b"; String s2 = a + b;
2. 可变字符串类对比(核心)
| 类名 | 线程安全 | 效率 | 使用场景 |
|---|
| StringBuilder | 非安全 | 最高 | 单线程大量拼接 |
| StringBuffer | 安全 | 较低 | 多线程字符串操作 |
代码示例:可变字符串拼接
public class StringBuildTest { public static void main(String[] args) { // 推荐:单线程使用StringBuilder StringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(" "); sb.append("Java"); String result = sb.toString(); System.out.println(result); // Hello Java } }
四、常用 API
1. String 对象创建机制
- 直接赋值:
String s = "abc" - new 关键字:
String s = new String("abc")- 堆中创建 1 个对象
- 常量池中不存在则再创建 1 个(总共最多 2 个)
2. == 与 equals 的区别
| 符号 / 方法 | 基本数据类型 | 引用数据类型 |
|---|
== | 比较值 | 比较内存地址 |
equals() | 不使用 | Object:比较地址;String:重写后比较内容 |
String s1 = "abc"; String s2 = new String("abc"); System.out.println(s1 == s2); // false(地址不同) System.out.println(s1.equals(s2)); // true(内容相同)
3. String 常用 API
基础操作
String str = "helloJava"; // 1. 获取指定下标字符 char c = str.charAt(2); // 'l' // 2. 获取字符串长度 int len = str.length(); // 9
字符串处理
// 1. 分割字符串 String[] arr = "a,b,c".split(","); // [a,b,c] // 2. 替换字符 String replaceStr = "hello".replace('l', 'x'); // hexxo // 3. 截取字符串 [begin, end) String sub = str.substring(2, 5); // llo
类型转换
String str = "abc"; // 字符串转字节数组(网络IO、编码常用) byte[] bytes = str.getBytes();