一、static(静态关键字)
1. 核心概念
static修饰的成员(变量、方法、代码块、内部类)属于类本身,而不是类的某个实例(对象)。
- 比喻:班级的公共饮水机(static),属于整个班级,所有同学(对象)都能使用,且只有 1 份;而每个同学的水杯(非 static),属于各自的实例,有多个副本。
- 内存角度:static 成员在类加载时就被初始化,存放在方法区(而非堆内存),生命周期与类一致,直到 JVM 卸载该类。
2. 常见用法及示例
(1)static 变量(类变量)
- 所有实例共享同一个 static 变量,修改一个实例的 static 变量,其他实例的该变量也会同步变化。
- 访问方式:
类名.变量名(推荐)或对象名.变量名(不推荐,易混淆)。 - 命名规范:通常配合
final使用(常量),全大写,下划线分隔;普通 static 变量小写开头。
java
运行
public class Student {
// 非static变量(实例变量):每个学生有独立的姓名
private String name;
// static变量(类变量):所有学生共享同一个班级名称,只有1份
public static String className = "高一(1)班";
public Student(String name) {
this.name = name;
}
public static void main(String[] args) {
Student s1 = new Student("张三");
Student s2 = new Student("李四");
// 访问static变量:推荐用类名访问
System.out.println(Student.className); // 输出:高一(1)班
// 修改static变量
Student.className = "高一(2)班";
// 所有实例的static变量都被修改
System.out.println(s1.className); // 输出:高一(2)班
System.out.println(s2.className); // 输出:高一(2)班
}
}
(2)static 方法(类方法)
- 属于类,无需创建对象即可调用(
类名.方法名)。 - 核心限制:不能直接访问非 static 成员 (因为 static 方法没有
this引用,无法指向具体实例),但可以访问 static 成员。 - 典型场景:工具类方法(如
Math.random()、Arrays.sort())、工具性操作(如对象创建的静态工厂方法)。
java
运行
public class Calculator {
// static方法:无需创建Calculator对象即可调用
public static int add(int a, int b) {
// 可以访问static成员,不能访问非static成员
return a + b;
}
// 非static方法:必须创建对象才能调用
public int subtract(int a, int b) {
return a - b;
}
public static void main(String[] args) {
// 调用static方法:直接用类名
int sum = Calculator.add(10, 20);
System.out.println(sum); // 输出:30
// 调用非static方法:必须创建对象
Calculator cal = new Calculator();
int diff = cal.subtract(20, 10);
System.out.println(diff); // 输出:10
}
}
(3)static 代码块
- 类加载时执行,且只执行一次(无论创建多少个实例)。
- 用于初始化 static 变量(如加载配置、初始化静态资源)。
java
运行
public class Config {
public static String DB_URL;
// static代码块:类加载时执行,初始化静态变量
static {
System.out.println("static代码块执行");
DB_URL = "jdbc:mysql://localhost:3306/test";
}
public static void main(String[] args) {
// 首次访问类,触发类加载,执行static代码块
System.out.println(Config.DB_URL); // 输出:static代码块执行 + jdbc:mysql://localhost:3306/test
// 再次创建实例,static代码块不会重复执行
Config c1 = new Config();
Config c2 = new Config();
}
}
(4)static 内部类
- 属于外部类本身,无需依赖外部类的实例即可创建。
- 不能访问外部类的非 static 成员(只能访问 static 成员)。
java
运行
public class OuterClass {
private static String staticField = "静态字段";
private String nonStaticField = "非静态字段";
// static内部类
public static class StaticInnerClass {
public void print() {
// 可以访问外部类的static成员
System.out.println(staticField);
// 错误:不能访问外部类的非static成员
// System.out.println(nonStaticField);
}
}
public static void main(String[] args) {
// 创建static内部类:无需外部类实例
OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();
inner.print(); // 输出:静态字段
}
}
二、final(最终关键字)
1. 核心概念
final表示 "最终的、不可改变的",修饰不同成员时,含义略有差异,但核心都是 "不可修改"。
- 比喻:刻在石碑上的文字(final 变量)无法修改;密封的箱子(final 方法)无法被打开重写;绝版的书籍(final 类)无法再版(继承)。
2. 常见用法及示例
(1)final 变量(常量)
- 一旦赋值,不可修改(引用类型变量:引用不可变,但对象内容可变)。
- 初始化要求:
- 局部 final 变量:声明时或使用前赋值即可;
- 成员 final 变量:必须在声明时、构造方法、初始化块中赋值(三者选其一),且只能赋值一次。
- 命名规范:final 常量(通常配合 static)全大写,下划线分隔(如
PI、MAX_VALUE)。
java
运行
public class FinalDemo {
// 1. 成员final变量:声明时直接赋值(推荐)
private final String NAME = "张三";
// 2. 成员final变量:构造方法中赋值
private final int AGE;
// 3. static final常量(类级常量,最常用)
public static final double PI = 3.1415926;
public FinalDemo(int age) {
this.AGE = age; // 构造方法中初始化final变量
}
public static void main(String[] args) {
FinalDemo demo = new FinalDemo(18);
// 错误:final变量不可修改
// demo.NAME = "李四";
// demo.AGE = 20;
// 引用类型final变量:引用不可变,但对象内容可变
final StringBuilder sb = new StringBuilder("hello");
sb.append(" world"); // 合法:修改对象内容
System.out.println(sb); // 输出:hello world
// 错误:引用不可变
// sb = new StringBuilder("new");
// static final常量:类名访问,不可修改
System.out.println(FinalDemo.PI); // 输出:3.1415926
}
}
(2)final 方法
- 不能被子类重写(override),保证方法的逻辑稳定(如父类的核心业务逻辑不允许子类修改)。
java
运行
public class Parent {
// final方法:子类不能重写
public final void sayHello() {
System.out.println("Hello from Parent");
}
}
public class Child extends Parent {
// 错误:无法重写final方法
// @Override
// public void sayHello() {
// System.out.println("Hello from Child");
// }
public static void main(String[] args) {
Child child = new Child();
child.sayHello(); // 输出:Hello from Parent
}
}
(3)final 类
- 不能被继承(extend) ,保证类的完整性(如 Java 核心类
String、Math、Integer都是 final 类,避免被篡改)。
java
运行
// final类:不能被继承
public final class FinalClass {
public void print() {
System.out.println("这是final类的方法");
}
}
// 错误:无法继承final类
// public class SubClass extends FinalClass {
// }
三、static final 组合使用(最常用)
static final修饰的变量是类级常量,具备两大特性:
static:属于类,内存中只有 1 份,类加载时初始化;final:一旦赋值,不可修改。
- 典型场景:定义系统常量(如
Math.PI、Integer.MAX_VALUE)。
java
运行
public class Constants {
// 数据库连接常量
public static final String DB_URL = "jdbc:mysql://localhost:3306/test";
public static final String DB_USER = "root";
public static final String DB_PWD = "123456";
// 工具类:私有化构造方法,避免创建实例
private Constants() {}
}
总结
- static 核心:属于类而非实例,类加载时初始化,所有实例共享,可通过类名直接访问;常用于工具方法、共享变量、静态初始化。
- final 核心:"不可变",修饰变量则值 / 引用不可改,修饰方法则不可重写,修饰类则不可继承;常用于定义常量、保护核心逻辑 / 类结构。
- static final:类级常量,内存唯一且不可修改,是 Java 中定义常量的标准方式。