目录
static 关键字
static 是 Java 中一个非常重要的关键字,它可以用来修饰变量、方法、代码块和内部类。不能修饰外部类(顶级类,Top-Level Class),static不能修饰构造器
外部类
- static 表示"属于类而不属于实例",但外部类本身就是一个独立的类,没有"所属对象"的概念,所以 static 修饰无意义。
- Java 语法规定,外部类只能用 public、final、abstract 或无修饰符(default 包访问权限)修饰,不能用 static。
static 的主要用法
1.静态变量(类变量)
- 用 static 修饰的变量属于类,而不是类的某个实例
- 所有实例共享同一个静态变量
- 在类加载时初始化
2 静态方法
- 静态方法属于类,而不是类的实例
- 可以直接通过类名调用
- 静态方法中不能直接访问非静态成员(变量或方法) 静态方法不能直接调用非静态方法,因为静态方法在执行时,没有类的实例上下文,无法访问实例变量和实例方法。如果静态方法需要调用非静态方法,可以通过创建类的实例来间接调用。
- 在 Java 中,静态方法本身并不需要 “初始化”,因为它们是类的一部分,而不是实例的一部分。静态方法在类加载到 JVM 时就可以被调用。不过,如果静态方法依赖于静态变量或静态代码块初始化的值,那么这些静态变量和静态代码块会在类加载时初始化。
3 静态代码块
- 用于初始化静态变量
- 在类加载时执行,且只执行一次
- 可以有多个静态代码块,按顺序执行
4 静态内部类
- 静态内部类不依赖于外部类的实例
- 可以访问外部类的静态成员
- 不能访问外部类的非静态成员
static 的注意事项
1 生命周期
- 静态成员的生命周期与类相同,从类加载开始到程序结束
- 非静态成员的生命周期与对象实例相同
2 访问限制
静态方法中:
- 可以直接访问其他静态成员
- 不能直接访问非静态成员(需要通过对象实例访问)
- 不能使用 this 和 super 关键字(这两个关键字是对象层面的)
3 内存分配
- 静态成员存储在方法区(Method Area)中
- 非静态成员存储在堆内存中
4 在 JVM 层面:
- 类初始化由 <clinit> 方法处理(静态代码块和静态变量初始化)
- 对象构造由 <init> 方法处理(构造器代码)
5 继承与覆盖
- 静态方法可以被继承,但不能被覆盖(Override)
- 子类中的同名静态方法会隐藏(Hide)父类的静态方法
class Parent {
static void show() {
System.out.println("Parent");
}
}
class Child extends Parent {
static void show() {
System.out.println("Child");
}
}
public class Test {
public static void main(String[] args) {
Parent p = new Child();
p.show(); // 输出 "Parent",不是多态
}
}
6 线程安全
- 静态变量是共享资源,在多线程环境下需要考虑线程安全问题
- 可以使用同步机制(synchronized)或 volatile 关键字保证线程安全
使用场景
- 工具类方法:如 Math 类中的各种数学计算方法
- 常量定义:使用 static final 组合定义常量
- 共享数据:需要在所有实例间共享的数据
- 单例模式:实现单例设计模式
- 工厂方法:创建对象的静态工厂方法
final 关键字
final 是 Java 中一个非常重要的关键字,它可以用来修饰类、方法、变量(包括局部变量、成员变量和静态变量)。不能修饰构造器
final 的基本用法
1 final 修饰类
当一个类被声明为 final 时,它不能被继承。
应用:
- String 类就是 final 的,确保其不可变性(非唯一原因,但是关键防御手段)
- 工具类通常声明为 final 防止被继承
2 final 修饰方法
final 方法不能被子类覆盖\重写(Override)。
应用:
- 不希望子类改变的方法
- 模板方法设计模式中的固定步骤
3 final 修饰变量
final 变量一旦被初始化后就不能再修改。
(1 )基本类型变量:
final int x = 10;
x = 20; // 编译错误:Cannot assign a value to final variable 'x'
(2)引用类型变量
final List<String> list = new ArrayList<>();
list.add("Hello"); // 允许,修改的是对象内容
list = new ArrayList<>(); // 编译错误:Cannot assign a value to final variable 'list'
(3)final 参数
void process(final int param) {//由调用方法时传入的值初始化
param = 10; // 编译错误
}
final 成员变量
必须在声明时或构造器或代码块中初始化:
但注意在构造器中初始化的时候,每个构造器都要加初始化语句(这可以用代码块优化)
class MyClass {
final int x; // 1.可以在定义时直接赋值
{
x=0; //2.代码块中初始化
}
// MyClass(int value) {//3.构造器中赋值
// x = value;
// }
}
final 静态变量
必须在声明或静态代码块中初始化;不能在构造器中初始化。
final 的注意事项
1 final 与不可变性
- final 修饰基本类型:值不可变
- final 修饰引用类型:引用不可变,但对象内容可变
要实现完全不可变类,需要:
- 所有字段 final
- 类本身 final(或构造器 private) ,这里类final修饰了,方法就可以不用final了
- 不提供修改内部状态的方法
2 初始化时机
- final 实例变量必须在构造完成前初始化
- final 静态变量必须在类加载完成前初始化
3 final+static
final和static往往搭配使用,效率更高,不会导致类加载(只调用类中的final+static修饰的常量时,不会导致类被加载)
4 final类不能被继承,但可以实例化对象
5.final 变量初始化的两种场景(成员变量和局部变量)
| 特性 | final 成员变量 | final 局部变量 |
|---|---|---|
| 初始化要求 | 必须在声明、构造器或初始化块中赋值 | 只需在使用前赋值一次 |
| 作用域 | 整个类范围内有效 | 仅在声明它的代码块内有效 |
| 默认值 | 无(必须显式初始化) | 无(必须显式初始化) |
| 典型用途 | 定义不可变对象属性 | 确保局部计算过程中值不被修改 |
局部变量:
void example() {
final int x; // 声明时不初始化(空白final)
x = 10; // 第一次赋值
// x = 20; // 编译错误:不能再次赋值
System.out.println(x);
}
void process(boolean flag) {
final int result;
if (flag) {
result = 1;
} else {
result = 2;
}
System.out.println(result); // 确保在任何路径下都已初始化
}
void loadConfig() {
final String config;
try {
config = readConfigFile(); // 可能抛出异常
} catch (IOException e) {
config = "default"; // 确保异常情况下也有值
}
System.out.println(config);
}
使用场景
- 尽量使用 final 修饰不会改变的变量:提高代码可读性和安全性
- 不可变类优先使用 final 字段:简化并发编程
- 工具类声明为 final:防止被继承
- 常量使用 public static final:遵循命名规范(全大写,下划线分隔)
常见误区
- 认为 final 对象完全不可变:实际只是引用不可变
- 忽略空白 final 的初始化要求:导致编译错误
补充:String 不可变的真正原因
| 关键设计 | 作用 |
|---|---|
1. final 修饰类 | 防止子类继承并重写方法破坏不可变性(如覆盖 toCharArray() 返回可变数组)。 |
2. private final 字段 | 存储字符数据的 char[] value 是 private final,外部无法直接修改。 |
| 3. 无修改数据的公开方法 | 所有看似修改的方法(如 concat()、replace())都返回新 String 对象。 |
| 4. 保护性拷贝 | 构造 String 时,如果传入外部 char[],会拷贝一份新数组(避免外部修改影响)。 |
970

被折叠的 条评论
为什么被折叠?



