杰瑞科技汇

Java static关键字何时该用?

当你希望某个东西(变量、方法、代码块、内部类)不依赖于具体的对象,而是被所有对象共享,或者通过类名直接访问时,就应该使用 static

Java static关键字何时该用?-图1
(图片来源网络,侵删)

下面我们从几个方面详细解释 static 的使用场景。


静态变量

用途:声明一个类级别的变量,该变量被所有该类的实例共享

特点

  • 内存存储:静态变量存储在方法区的静态存储区,而不是堆中,整个类只有一份拷贝。
  • 生命周期:随着类的加载而创建,随着类的卸载而销毁,生命周期比对象长。
  • 访问方式:可以通过 类名.变量名对象名.变量名 访问,但推荐使用前者,因为它更清晰地表明这是一个静态成员。

使用场景: 当所有对象都需要共享同一个数据时。

Java static关键字何时该用?-图2
(图片来源网络,侵删)

示例

public class Student {
    // 每个学生都有自己的名字和年龄,这些是实例变量
    private String name;
    private int age;
    // 学校名称是所有学生共享的,所以用 static
    private static String schoolName = "清华大学";
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void study() {
        System.out.println(this.name + " 正在 " + schoolName + " 学习。");
    }
    public static void main(String[] args) {
        Student s1 = new Student("张三", 20);
        Student s2 = new Student("李四", 21);
        s1.study(); // 输出: 张三 正在 清华大学 学习。
        s2.study(); // 输出: 李四 正在 清华大学 学习。
        // 修改学校名称,会影响所有学生
        Student.schoolName = "北京大学";
        s1.study(); // 输出: 张三 正在 北京大学 学习。
        s2.study(); // 输出: 李四 正在 北京大学 学习。
    }
}

什么时候不用:如果每个对象都需要拥有自己独立的副本(比如每个学生的学号),那么就应该使用实例变量,而不是静态变量。


静态方法

用途:声明一个属于类的方法,而不是属于某个对象的方法。

特点

Java static关键字何时该用?-图3
(图片来源网络,侵删)
  • 访问限制:静态方法只能访问静态变量和静态方法,它不能直接访问实例变量和实例方法,因为它没有 this 引指向任何具体对象。
  • 调用方式:可以通过 类名.方法名() 直接调用,无需创建对象。

使用场景

  1. 工具类方法:当一个方法不依赖于任何对象的状态(实例变量)时,可以将其设为静态。java.lang.Math 中的 Math.max(), java.util.Arrays 中的 Arrays.sort()
  2. 工厂方法:用于创建和返回对象实例,如 java.util.Collections 中的 emptyList()
  3. 入口方法:程序的入口点 public static void main(String[] args) 必须是静态的,因为它需要在创建任何对象之前由 JVM 调用。

示例

public class MathUtils {
    // 这个方法不依赖于任何对象状态,所以是静态的
    public static int add(int a, int b) {
        return a + b;
    }
    // 这个方法依赖于实例变量 result,所以不能是静态的
    private int result;
    public void accumulate(int num) {
        this.result += num;
    }
}
public class Main {
    public static void main(String[] args) {
        // 直接通过类名调用,无需创建 MathUtils 对象
        int sum = MathUtils.add(10, 20);
        System.out.println("Sum is: " + sum); // 输出: Sum is: 30
    }
}

静态初始化块

用途:在类加载时执行一次,用于初始化静态变量。

特点

  • 执行时机:当 JVM 加载类时,按顺序执行静态块,一个类可以有多个静态块,它们按在代码中出现的顺序执行。
  • 执行次数:每个类只执行一次。

使用场景: 当初始化静态变量需要复杂的逻辑(如读取配置文件、建立数据库连接等)时,可以使用静态代码块。

示例

public class DatabaseConfig {
    private static String dbUrl;
    private static String dbUser;
    private static String dbPassword;
    // 静态代码块,用于初始化静态变量
    static {
        System.out.println("正在加载数据库配置...");
        // 模拟从配置文件读取
        dbUrl = "jdbc:mysql://localhost:3306/mydb";
        dbUser = "root";
        dbPassword = "password";
        System.out.println("数据库配置加载完成。");
    }
    public static void printConfig() {
        System.out.println("URL: " + dbUrl);
        System.out.println("User: " + dbUser);
    }
    public static void main(String[] args) {
        // 第一次访问类时,静态块会执行
        DatabaseConfig.printConfig(); 
        // 第二次访问,静态块不会再次执行
        DatabaseConfig.printConfig();
    }
}

输出

正在加载数据库配置...
数据库配置加载完成。
URL: jdbc:mysql://localhost:3306/mydb
User: root
URL: jdbc:mysql://localhost:3306/mydb
User: root

静态内部类

用途:将一个内部类声明为 static

特点

  • 与外部类的关联:静态内部类不持有对外部类对象的隐式引用(即没有 外部类.this),它可以独立于外部类对象存在。
  • 创建方式:可以直接通过 外部类名.内部类名 来创建实例,无需先创建外部类对象。

使用场景: 当一个内部类不依赖于外部类的实例状态时,使用静态内部类可以避免不必要的内存开销(因为不会创建外部类的引用)。

示例

public class OuterClass {
    private String outerField = "Outer field";
    // 非静态内部类(成员内部类)
    class InnerClass {
        public void display() {
            // 可以访问外部类的成员
            System.out.println(outerField);
        }
    }
    // 静态内部类
    static class StaticInnerClass {
        // 不能直接访问外部类的非静态成员 outerField
        // System.out.println(outerField); // 编译错误!
        public static void staticDisplay() {
            System.out.println("This is a static inner class method.");
        }
    }
}
public class Main {
    public static void main(String[] args) {
        // 创建静态内部类的实例,不需要 OuterClass 的实例
        OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
        staticInner.staticDisplay(); // 输出: This is a static inner class method.
        // 创建非静态内部类的实例,必须先有 OuterClass 的实例
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.display(); // 输出: Outer field
    }
}

总结与何时使用

成员类型 何时使用 关键特点
静态变量 当某个数据被所有实例共享时。 类级别,一份拷贝,生命周期长。
静态方法 当方法不依赖对象状态,或作为工具方法、工厂方法时。 只能访问静态成员,可通过类名直接调用。
静态代码块 在类加载时执行一次,用于复杂初始化。 按顺序执行,每个类只执行一次。
静态内部类 当内部类不依赖外部类实例时。 不持有外部类引用,可独立创建。

重要的注意事项

  1. 线程安全:静态变量是共享的,在多线程环境下对其进行修改需要注意线程安全问题。
  2. 内存泄漏:静态变量生命周期很长,如果它持有一个对大对象的引用(如集合、IO流等),可能会导致这些对象无法被垃圾回收,从而造成内存泄漏。
  3. 滥用 static:不要为了方便而滥用 static,如果一个方法或变量明显是属于某个特定对象的(BankAccountbalance),就应该使用非静态的实例成员,过度使用 static 会使代码变得难以测试和维护,因为它增加了类之间的耦合性。
分享:
扫描分享到社交APP
上一篇
下一篇