Java static关键字核心知识点随堂笔记
前言
本篇笔记承接上一篇Java面向对象核心内容,完整复盘课堂讲解的static关键字知识点,梳理其核心特性、三大修饰场景、执行优先级规则,同时对课堂代码做语法规范与执行流程拆解,补充新手易踩坑的注意事项,适配Java入门复盘与巩固需求。
一、static关键字的核心本质
在Java中,类是创建对象的模板 ,普通的成员变量、成员方法归属于具体的对象,每个对象创建后都会拥有独立的副本,互不影响;而static关键字的核心作用,就是将修饰的内容从对象级别提升到类级别。
核心定义总结:
static修饰的变量、方法、代码块,均归属于类本身,而非某个具体的实例对象,在JVM加载类时完成初始化,整个程序生命周期中仅会初始化一次,且被该类创建的所有对象共享。
核心区别补充:
- 非static内容(实例成员):必须创建对象后才能访问,生命周期与对象绑定,每个对象有独立副本
- static内容(静态成员):无需创建对象,直接通过类名即可访问,生命周期与类绑定,全类仅存一份
二、static的三大核心修饰场景
2.1 static修饰成员变量(静态变量/类变量)
核心定义
使用static修饰的成员变量,称为静态变量(也叫类变量),区别于无static修饰的实例变量。
核心特性
- 全类共享:静态变量在JVM方法区中仅存储一份,该类创建的所有对象共享同一份值,任意一个对象修改了静态变量,其他所有对象获取到的都是修改后的值
- 调用规则 :推荐直接使用
类名.变量名调用,也可通过对象调用(不推荐,编译器会触发警告) - 生命周期:随类的加载完成初始化,随类的卸载而销毁,生命周期远长于实例对象
代码示例
java
package qcby;
public class Person {
// 实例变量:每个对象有独立副本,互不影响
private String name;
// 静态变量:全类所有对象共享同一份
public static String country = "中国";
public Person(String name) {
this.name = name;
}
public static void main(String[] args) {
Person p1 = new Person("张三");
Person p2 = new Person("李四");
// 推荐用法:类名直接调用静态变量
System.out.println(Person.country); // 输出:中国
// 通过对象访问静态变量(不推荐)
System.out.println(p1.country); // 输出:中国
System.out.println(p2.country); // 输出:中国
// 任意对象修改静态变量,全类共享的内容都会变更
p1.country = "美国";
System.out.println(p2.country); // 输出:美国
System.out.println(Person.country); // 输出:美国
}
}
2.2 static修饰成员方法(静态方法/类方法)
核心定义
使用static修饰的成员方法,称为静态方法(也叫类方法),是类级别的方法,无需依赖对象即可调用。
核心特性
- 调用规则 :无需创建对象,直接通过
类名.方法名()调用,是工具类的核心实现方式 - 访问限制(核心) :
- 静态方法中,不能直接访问实例变量和实例方法(实例成员必须依赖对象存在,而静态方法执行时可能还未创建对象)
- 静态方法中,只能直接访问静态变量和其他静态方法
- 反过来,实例方法中可以直接访问所有静态成员和实例成员
- 关键字限制 :静态方法中不能使用
this、super关键字(两个关键字均指代实例对象,静态方法无对象依赖)
代码示例
java
package qcby;
/**
* 静态方法典型场景:工具类
*/
public class CalculatorUtils {
// 静态工具方法:无需创建对象,直接类名调用
public static int add(int a, int b) {
return a + b;
}
public static int sub(int a, int b) {
return a - b;
}
// 实例方法
public void show() {
// 实例方法可直接调用静态方法
System.out.println(add(10, 20));
}
public static void main(String[] args) {
// 直接类名调用,无需new对象
int sum = CalculatorUtils.add(5, 3);
System.out.println(sum); // 输出:8
// 错误示例:静态方法中不能直接调用实例方法/实例变量
// show(); 编译报错
}
}
2.3 static修饰静态代码块
核心定义
使用static{}包裹的代码片段,称为静态代码块,是类级别的初始化代码。
核心特性
- 执行时机 :在类被JVM加载时自动执行,且整个程序生命周期中仅会执行一次
- 执行优先级 :优先级极高,早于main方法执行,早于构造方法执行,早于任何对象创建
- 执行顺序 :同一个类中,多个静态代码块、静态成员变量的初始化,严格按照代码书写的从上到下的顺序执行
- 核心用途:用于类的全局初始化操作,比如加载配置文件、初始化静态资源、注册驱动等,避免每次创建对象都重复执行初始化逻辑,优化程序性能
三、课堂核心代码执行顺序全拆解
本次课堂的核心重点是静态代码块的执行顺序,以下针对两个课堂示例做完整的流程拆解,彻底理清执行规则。
3.1 继承场景下:静态代码块+构造方法的执行顺序
规范后的课堂代码
java
package qcby;
/**
* 继承场景下静态内容与构造方法执行顺序测试
* 核心规则:先加载父类,再加载子类;先执行父类构造,再执行子类构造
*/
public class Test extends Base{
// 子类静态代码块
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public void run(){
}
public static void main(String[] args) {
new Test();
}
}
/**
* 父类
*/
class Base{
// 父类静态代码块
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
执行结果
base static
test static
base constructor
test constructor
完整执行流程拆解
- 程序入口触发 :执行
Test类的main方法,JVM需要先加载Test类到内存中 - 类加载阶段(静态内容执行) :
- 发现
Test类继承自Base父类,JVM会优先加载父类Base ,加载时执行父类的静态代码块,输出base static - 父类加载完成后,再加载子类
Test,执行子类的静态代码块,输出test static - 静态内容仅在类第一次加载时执行一次,后续无论创建多少个对象,都不会再次执行
- 发现
- 对象创建阶段(构造方法执行) :
- 类加载完成后,执行
main方法中的new Test(),创建子类对象 - 创建子类对象时,会优先调用父类的构造方法 ,完成父类对象的初始化,输出
base constructor - 父类构造执行完成后,再调用子类的构造方法,完成子类对象初始化,输出
test constructor
- 类加载完成后,执行
继承场景执行规则总结
- 静态内容执行:先父类静态 → 子类静态,仅在类第一次加载时执行一次
- 构造方法执行:先父类构造 → 子类构造,每次创建对象都会执行
- 所有静态内容的执行,永远早于所有构造方法的执行
3.2 同个类中:静态成员与静态代码块的执行顺序
规范后的课堂代码
java
package qcby;
public class Demo {
// 第一个静态代码块
static {
System.out.println("11");
}
// 静态成员变量初始化
public static Demo demo = new Demo("+++");
// 第二个静态代码块
static {
System.out.println("22");
}
// 构造方法
public Demo(String aa){
System.out.println("===="+aa);
}
}
class Test0{
public static void main(String[] args) {
// 触发Demo类加载 + 创建Demo对象
Demo demo = new Demo("----");
}
}
执行结果
11
====+++
22
====----
完整执行流程拆解
- 程序入口触发 :执行
Test0的main方法,执行new Demo("----")时,JVM需要先加载Demo类 - 类加载阶段(静态内容按顺序执行) :
- 按照代码书写的从上到下的顺序,先执行第一个静态代码块,输出
11 - 接着执行静态成员变量
demo的初始化,执行new Demo("+++"),调用构造方法,输出====+++ - 最后执行第二个静态代码块,输出
22 - 至此,Demo类加载完成,所有静态内容执行完毕,且仅执行这一次
- 按照代码书写的从上到下的顺序,先执行第一个静态代码块,输出
- 对象创建阶段 :
- 类加载完成后,执行
main方法中的new Demo("----"),调用构造方法,输出====----
- 类加载完成后,执行
同个类执行规则总结
同一个类中,静态变量初始化、静态代码块,严格按照代码书写的先后顺序执行,全部在类加载阶段完成,仅执行一次;构造方法在每次创建对象时执行,永远晚于所有静态内容。
四、static使用的核心避坑点
- 静态方法不能被重写:静态方法属于类,重写是基于对象的多态特性,子类可以定义和父类同名的静态方法,但这只是隐藏,并非重写,不具备多态效果
- 多线程线程安全问题 :静态变量被所有线程共享,多线程环境下同时修改静态变量,会出现上节课讲解的
count++数据覆盖问题,需做好同步控制 - 静态代码块的使用限制:静态代码块中只能操作静态成员,不能直接访问实例成员,也不能抛出检查型异常
- 内存泄漏风险:静态变量的生命周期和类一致,若静态变量中存储了大对象,会导致对象无法被垃圾回收,容易引发内存泄漏
五、笔记核心总结
- 核心本质 :
static将修饰的内容从对象级别提升到类级别,归属于类本身,全类共享,类加载时初始化,仅执行一次 - 三大场景 :
- 静态变量:存储类级别的共享数据,全类仅一份
- 静态方法:无需创建对象即可调用,是工具类的核心实现
- 静态代码块:类加载时自动执行,用于类的全局初始化,优先级最高
- 执行顺序铁律:静态内容永远早于构造方法执行;继承场景先父类静态、再子类静态,先父类构造、再子类构造;同个类中静态内容按书写顺序执行
- 访问限制:静态内容不能直接访问非静态内容,非静态内容可直接访问静态内容