Java 基础笔记(二)

Java static关键字核心知识点随堂笔记

前言

本篇笔记承接上一篇Java面向对象核心内容,完整复盘课堂讲解的static关键字知识点,梳理其核心特性、三大修饰场景、执行优先级规则,同时对课堂代码做语法规范与执行流程拆解,补充新手易踩坑的注意事项,适配Java入门复盘与巩固需求。

一、static关键字的核心本质

在Java中,类是创建对象的模板 ,普通的成员变量、成员方法归属于具体的对象,每个对象创建后都会拥有独立的副本,互不影响;而static关键字的核心作用,就是将修饰的内容从对象级别提升到类级别

核心定义总结:
static修饰的变量、方法、代码块,均归属于类本身,而非某个具体的实例对象,在JVM加载类时完成初始化,整个程序生命周期中仅会初始化一次,且被该类创建的所有对象共享。

核心区别补充:

  • 非static内容(实例成员):必须创建对象后才能访问,生命周期与对象绑定,每个对象有独立副本
  • static内容(静态成员):无需创建对象,直接通过类名即可访问,生命周期与类绑定,全类仅存一份

二、static的三大核心修饰场景

2.1 static修饰成员变量(静态变量/类变量)

核心定义

使用static修饰的成员变量,称为静态变量(也叫类变量),区别于无static修饰的实例变量。

核心特性
  1. 全类共享:静态变量在JVM方法区中仅存储一份,该类创建的所有对象共享同一份值,任意一个对象修改了静态变量,其他所有对象获取到的都是修改后的值
  2. 调用规则 :推荐直接使用类名.变量名调用,也可通过对象调用(不推荐,编译器会触发警告)
  3. 生命周期:随类的加载完成初始化,随类的卸载而销毁,生命周期远长于实例对象
代码示例
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修饰的成员方法,称为静态方法(也叫类方法),是类级别的方法,无需依赖对象即可调用。

核心特性
  1. 调用规则 :无需创建对象,直接通过类名.方法名()调用,是工具类的核心实现方式
  2. 访问限制(核心)
    • 静态方法中,不能直接访问实例变量和实例方法(实例成员必须依赖对象存在,而静态方法执行时可能还未创建对象)
    • 静态方法中,只能直接访问静态变量和其他静态方法
    • 反过来,实例方法中可以直接访问所有静态成员和实例成员
  3. 关键字限制 :静态方法中不能使用thissuper关键字(两个关键字均指代实例对象,静态方法无对象依赖)
代码示例
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{}包裹的代码片段,称为静态代码块,是类级别的初始化代码。

核心特性
  1. 执行时机在类被JVM加载时自动执行,且整个程序生命周期中仅会执行一次
  2. 执行优先级 :优先级极高,早于main方法执行,早于构造方法执行,早于任何对象创建
  3. 执行顺序 :同一个类中,多个静态代码块、静态成员变量的初始化,严格按照代码书写的从上到下的顺序执行
  4. 核心用途:用于类的全局初始化操作,比如加载配置文件、初始化静态资源、注册驱动等,避免每次创建对象都重复执行初始化逻辑,优化程序性能

三、课堂核心代码执行顺序全拆解

本次课堂的核心重点是静态代码块的执行顺序,以下针对两个课堂示例做完整的流程拆解,彻底理清执行规则。

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
完整执行流程拆解
  1. 程序入口触发 :执行Test类的main方法,JVM需要先加载Test类到内存中
  2. 类加载阶段(静态内容执行)
    • 发现Test类继承自Base父类,JVM会优先加载父类Base ,加载时执行父类的静态代码块,输出base static
    • 父类加载完成后,再加载子类Test,执行子类的静态代码块,输出test static
    • 静态内容仅在类第一次加载时执行一次,后续无论创建多少个对象,都不会再次执行
  3. 对象创建阶段(构造方法执行)
    • 类加载完成后,执行main方法中的new Test(),创建子类对象
    • 创建子类对象时,会优先调用父类的构造方法 ,完成父类对象的初始化,输出base constructor
    • 父类构造执行完成后,再调用子类的构造方法,完成子类对象初始化,输出test constructor
继承场景执行规则总结
  1. 静态内容执行:先父类静态 → 子类静态,仅在类第一次加载时执行一次
  2. 构造方法执行:先父类构造 → 子类构造,每次创建对象都会执行
  3. 所有静态内容的执行,永远早于所有构造方法的执行

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
====----
完整执行流程拆解
  1. 程序入口触发 :执行Test0main方法,执行new Demo("----")时,JVM需要先加载Demo
  2. 类加载阶段(静态内容按顺序执行)
    • 按照代码书写的从上到下的顺序,先执行第一个静态代码块,输出11
    • 接着执行静态成员变量demo的初始化,执行new Demo("+++"),调用构造方法,输出====+++
    • 最后执行第二个静态代码块,输出22
    • 至此,Demo类加载完成,所有静态内容执行完毕,且仅执行这一次
  3. 对象创建阶段
    • 类加载完成后,执行main方法中的new Demo("----"),调用构造方法,输出====----
同个类执行规则总结

同一个类中,静态变量初始化、静态代码块,严格按照代码书写的先后顺序执行,全部在类加载阶段完成,仅执行一次;构造方法在每次创建对象时执行,永远晚于所有静态内容。

四、static使用的核心避坑点

  1. 静态方法不能被重写:静态方法属于类,重写是基于对象的多态特性,子类可以定义和父类同名的静态方法,但这只是隐藏,并非重写,不具备多态效果
  2. 多线程线程安全问题 :静态变量被所有线程共享,多线程环境下同时修改静态变量,会出现上节课讲解的count++数据覆盖问题,需做好同步控制
  3. 静态代码块的使用限制:静态代码块中只能操作静态成员,不能直接访问实例成员,也不能抛出检查型异常
  4. 内存泄漏风险:静态变量的生命周期和类一致,若静态变量中存储了大对象,会导致对象无法被垃圾回收,容易引发内存泄漏

五、笔记核心总结

  1. 核心本质static将修饰的内容从对象级别提升到类级别,归属于类本身,全类共享,类加载时初始化,仅执行一次
  2. 三大场景
    • 静态变量:存储类级别的共享数据,全类仅一份
    • 静态方法:无需创建对象即可调用,是工具类的核心实现
    • 静态代码块:类加载时自动执行,用于类的全局初始化,优先级最高
  3. 执行顺序铁律:静态内容永远早于构造方法执行;继承场景先父类静态、再子类静态,先父类构造、再子类构造;同个类中静态内容按书写顺序执行
  4. 访问限制:静态内容不能直接访问非静态内容,非静态内容可直接访问静态内容
相关推荐
papaofdoudou1 小时前
AMD-V 嵌套分页白皮书翻译
java·linux·服务器
海寻山1 小时前
Java 泛型 (Generic) 入门到精通:语法 + 原理 + 实战 + 避坑
java·windows·python
智者知已应修善业1 小时前
【51单片机数码管+蜂鸣器的使用】2023-6-14
c++·经验分享·笔记·算法·51单片机
2301_803538951 小时前
SQL如何避免不同团队修改同一张表_基于前缀名的授权GRANT ON语法
jvm·数据库·python
艾莉丝努力练剑2 小时前
【Linux线程】Linux系统多线程(七):<线程同步与互斥>线程同步(下)
java·linux·运维·服务器·c++·学习·操作系统
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【15】工具执行拦截器(ToolInterceptor)
java·人工智能·spring
m0_678485452 小时前
c++怎么在Windows下设置文件的安全访问控制列表(ACL)权限【底层】
jvm·数据库·python
ch.ju2 小时前
Java程序设计(第3版)第二章——逻辑运算符
java
喜欢流萤吖~2 小时前
SpringBoot 异步处理与线程池实战
java·开发语言