【Java SE】Java中的static关键字总结

Java中的static关键字总结

在Java编程语言中,static是一个非常重要的关键字,它用于定义类级别的成员。被static修饰的成员属于类本身,而不是类的某个具体实例。这意味着无论创建多少个类的对象,静态成员在内存中只有一份拷贝,被所有对象共享。本文将详细介绍Java中static的四种主要用法:静态变量、静态方法、静态初始化块和静态内部类。

静态变量(类变量)

定义与特点

静态变量 是使用static关键字修饰的变量,也称为类变量。它与普通实例变量的最大区别在于:

  1. 属于类而非对象:静态变量在内存中只有一个副本,被该类的所有对象共享
  2. 类加载时初始化:静态变量在类加载到JVM时完成初始化,且在整个程序运行期间只初始化一次
  3. 直接通过类名访问 :无需创建对象,直接使用类名.静态变量名的方式访问
java 复制代码
public class Counter {
    static int count = 0;  // 静态变量,记录创建的对象数量
    
    public Counter() {
        count++;  // 每次创建对象时,count增加
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("初始对象数量: " + Counter.count);  // 输出: 0,无需创建对象
        
        Counter obj1 = new Counter();
        System.out.println("创建obj1后: " + obj1.count);       // 输出: 1
        
        Counter obj2 = new Counter();
        System.out.println("创建obj2后: " + Counter.count);    // 输出: 2(使用类名访问)
    }
}

静态方法(类方法)

定义与特点

静态方法 是使用static关键字修饰的方法,也称为类方法。其主要特点包括:

  1. 类级别调用:可以直接通过类名调用,无需创建对象
  2. 访问限制:只能直接访问类的静态成员(静态变量和其他静态方法)
  3. 不能使用this和super:静态方法中不存在当前对象的引用

访问限制的深入理解

静态方法不能直接访问实例成员的根本原因在于生命周期不同:静态方法在类加载时就存在,而实例成员只有在对象创建后才存在。如果需要在静态方法中访问实例成员,必须先创建对象。

java 复制代码
public class Demo {
    int instanceVar = 20;  // 实例变量
    
    void instanceMethod() {
        System.out.println("实例方法被调用");
    }
    
    // 错误示例:静态方法直接访问实例成员
    static void wrongStaticMethod() {
        // System.out.println(instanceVar);  // 编译错误!
        // instanceMethod();                  // 编译错误!
    }
    
    // 正确示例:通过对象访问实例成员
    static void correctStaticMethod() {
        Demo obj = new Demo();  // 先创建对象
        System.out.println("通过对象访问实例变量: " + obj.instanceVar);
        obj.instanceMethod();    // 通过对象调用实例方法
    }
}

实用示例

java 复制代码
public class MathUtils {
    // 工具方法,无需创建对象即可使用
    public static int add(int a, int b) {
        return a + b;
    }
    
    public static double circleArea(double radius) {
        return Math.PI * radius * radius;
    }
}

public class Main {
    public static void main(String[] args) {
        int sum = MathUtils.add(5, 3);           // 直接通过类名调用
        double area = MathUtils.circleArea(2.5);  // 无需创建MathUtils对象
        
        System.out.println("5 + 3 = " + sum);      // 输出: 8
        System.out.println("圆面积: " + area);      // 输出: 19.634...
    }
}

静态初始化块

定义与特点

静态初始化块 是用static关键字修饰的代码块,用于执行类的初始化操作。其特点如下:

  1. 类加载时执行:当类第一次被加载到JVM时执行
  2. 只执行一次:在整个程序生命周期中仅执行一次
  3. 按顺序执行:如果有多个静态块,按在类中出现的顺序执行
  4. 优先于构造方法:静态块执行完毕后才会执行构造方法
java 复制代码
public class DatabaseConnection {
    static String connectionUrl;
    static int maxConnections;
  
    public DatabaseConnection() {
        System.out.println("构造方法执行");
    }
    // 静态初始化块 - 用于初始化静态资源
    static {
        System.out.println("静态初始化块开始执行");
        connectionUrl = "jdbc:mysql://localhost:3306/mydb";
        maxConnections = 10;
        System.out.println("数据库连接配置已完成");
    }
    
    // 另一个静态初始化块
    static {
        System.out.println("第二个静态初始化块执行");
        // 可以进行一些额外的初始化操作
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("main方法开始执行");
        
        // 第一次使用类,触发类加载,静态块执行
        DatabaseConnection conn1 = new DatabaseConnection();
        
        System.out.println("--- 分割线 ---");
        
        // 第二次创建对象,静态块不再执行
        DatabaseConnection conn2 = new DatabaseConnection();
    }
}

输出结果:

复制代码
main方法开始执行
静态初始化块开始执行
数据库连接配置已完成
第二个静态初始化块执行
构造方法执行
--- 分割线 ---
构造方法执行

应用场景

  • 加载数据库驱动
  • 读取配置文件
  • 初始化静态资源池
  • 执行只需一次的复杂初始化逻辑

静态内部类

定义与特点

静态内部类 是使用static修饰的内部类,它与普通内部类有显著区别:

  1. 不依赖外部类实例:可以直接创建静态内部类的对象,无需先创建外部类对象
  2. 访问限制:只能访问外部类的静态成员,不能直接访问实例成员
  3. 可包含静态成员:静态内部类可以有自己的静态变量和方法
  4. 外部类名访问 :通过外部类名.内部类名的方式访问
java 复制代码
public class Company {
    private static String companyName = "Tech Corp";
    private String address = "Beijing";
    
    // 静态内部类
    public static class Employee {
        private String name;
        private static int employeeCount = 0;  // 静态内部类可以有自己的静态成员
        
        public Employee(String name) {
            this.name = name;
            employeeCount++;
        }
        
        public void display() {
            // 可以访问外部类的静态成员
            System.out.println("公司名称: " + companyName);
            
            // 不能直接访问外部类的实例成员
            // System.out.println(address);  // 编译错误!
            
            System.out.println("员工姓名: " + name);
            System.out.println("员工总数: " + employeeCount);
        }
        
        public static void showCompanyInfo() {
            System.out.println("公司: " + companyName);
        }
    }
    
    // 非静态内部类(对比用)
    public class Department {
        private String deptName;
        
        public Department(String deptName) {
            this.deptName = deptName;
        }
        
        public void showInfo() {
            // 非静态内部类可以访问外部类的所有成员
            System.out.println("公司: " + companyName + ", 地址: " + address);
            System.out.println("部门: " + deptName);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建静态内部类对象 - 不需要外部类实例
        Company.Employee emp1 = new Company.Employee("张三");
        Company.Employee emp2 = new Company.Employee("李四");
        
        emp1.display();
        System.out.println("---");
        
        // 调用静态内部类的静态方法
        Company.Employee.showCompanyInfo();
        
        System.out.println("--- 分割线 ---");
        
        // 创建非静态内部类对象 - 需要先创建外部类实例
        Company company = new Company();
        Company.Department dept = company.new Department("技术部");
        dept.showInfo();
    }
}

应用场景

  • 辅助类的封装,当内部类不需要访问外部类实例成员时
  • 构建器模式(Builder Pattern)的实现
  • 与外部类逻辑紧密相关但可独立使用的工具类

static的核心特性

类型 属于 访问方式 初始化时机 内存特点
静态变量 类名.变量名 类加载时 一份拷贝,所有对象共享
静态方法 类名.方法名 类加载时 存储在方法区
静态块 自动执行 类加载时 执行后释放
静态内部类 外部类.内部类 使用时加载 独立于外部类实例

例题

例题1

以下代码的输出结果是?

java 复制代码
public class Test {
    public int aMethod() {
        static int i = 0;  // 这行有错误:static不能修饰局部变量
        i++;
        return i;
    }
    
    public static void main(String args[]) {
        Test test = new Test();
        test.aMethod();
        int j = test.aMethod();
        System.out.println(j);
    }
}

这个代码编译失败

错误分析

静态变量不能在方法内部声明

java 复制代码
public int aMethod() {
    static int i = 0;  // ❌ 错误:不能在方法内部使用static修饰局部变量
    i++;
    return i;
}

在Java中,static关键字不能用于修饰局部变量。静态变量属于类级别,必须在类中直接声明,而不能在方法、构造方法或代码块内部声明。

正确代码示例

如果要实现类似的功能(计数方法被调用的次数),正确的写法应该是:

java 复制代码
public class Test {
    static int i = 0;  // 静态变量定义在类中,而不是方法中
    
    public int aMethod() {
        i++;
        return i;
    }
    
    public static void main(String args[]) {
        Test test = new Test();
        test.aMethod();        // 第一次调用,i=1
        int j = test.aMethod(); // 第二次调用,i=2
        System.out.println(j);  // 输出 2
    }
}
相关推荐
kiki_241116 小时前
用IntelliJ IDEA编写Java程序,从0到1完整教程
java·ide·intellij-idea
FL162386312916 小时前
基于C#winform部署RealESRGAN的onnx模型实现超分辨率图片无损放大模糊图片变清晰
开发语言·c#
liuyao_xianhui16 小时前
优选算法_锯齿形层序遍历二叉树_队列_C++
java·开发语言·数据结构·c++·算法·链表
八宝粥大朋友16 小时前
Android sqlite3 编译及安装
android·java·sqlite
wxm63116 小时前
TCP监听--监听指定IP的端口号
java·网络·tcp/ip
csdn2015_16 小时前
java 把对象转化为json字符串
java·前端·json
想带你从多云到转晴16 小时前
03、数据结构与算法--单向链表
java·数据结构·算法
Elnaij16 小时前
从C++开始的编程生活(24)——C++11标准Ⅰ
开发语言·c++
无籽西瓜a16 小时前
【西瓜带你学设计模式 | 第七期 - 适配器模式】适配器模式 —— 类适配器与对象适配器实现、优缺点与适用场景
java·后端·设计模式·软件工程·适配器模式
mjhcsp16 小时前
AT_arc205_c [ARC205C] No Collision Moves 题解
开发语言·c++·算法·题解