在 Java 中,static 是一个关键字,用于表示“静态”的成员。它的核心作用是:让某个成员属于类本身,而不是类的某个具体实例。

简而言之:

  • 无需创建对象即可访问;
  • 所有实例共享同一个 static 成员。

下面分别说明 static 在不同场景下的作用:


1. 静态变量

比如:

public class Counter {
    public static int count = 0; // 静态变量
}
  • 静态属于类,所有对象共享同一个 count。
  • 即使没有创建 Counter 对象,也可以通过 Counter.count 访问。
  • 内存中只有一份副本,节省内存。

2. 静态方法

比如:

public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
}
  • 可以直接用 类名.方法名() 调用,如 MathUtils.add(3, 4)。
  • 不能访问非静态成员,因为非静态成员调用需要有对象的引用,而静态方法属于类,并没有这个引用。

我们常接触到的静态方法大多是工具类,不用创建工具实例就能直接使用工具方法,比如Arrays,Math。


3. 静态代码块

public class MyClass {
    static {
        System.out.println("静态代码块执行");
    }
}

因为静态代码块也属于类,随着类加载执行,且只执行一次,常用于初始化静态资源,如读取配置文件、初始化静态变量等。


4. 静态内部类

public class Outer {
    static class Inner {
        void display() {
            System.out.println("静态内部类");
        }
    }
}

当某个辅助类只在外部类中使用,且与外部类有紧密逻辑关系时,可以将其定义为静态内部类,避免污染全局命名空间。

在保持逻辑封装的同时,避免与外部类实例的强耦合,提升内存效率和使用灵活性。

但需要注意的是,静态内部类不持有外部类的引用,也就不能访问外部非静态成员。


5. main 方法为什么是 static?

public static void main(String[] args)

如果main方法不是static的,那么它就属于某个实例,那运行这个方法也需要依赖这个实例,又因为JVM 启动程序时,并没有创建类的实例,所以必须通过 static 方法直接调用。如果不是 static,JVM 就无法在没有对象的情况下启动程序。


6.需要注意的

static功能虽然很强大,但是使用时也存在一些风险,比如:
在这里插入图片描述

内存泄漏:把堆中的对象赋值给 static 变量,导致该对象被 GC Roots(即 static)强引用,因此本该被回收的对象无法被回收。
线程安全:显然static 变量在对象之间共享,会出现并发安全问题,可以看看如下代码:

public class Counter {
    private int count = 0; // 非 static

    public void increment() {
        count++;
    }
}

// 每个线程创建自己的 Counter
Thread t1 = new Thread(() -> {
    Counter c = new Counter(); // 线程1自己的对象
    c.increment();
});

Thread t2 = new Thread(() -> {
    Counter c = new Counter(); // 线程2自己的对象
    c.increment();
});

反对象设计:static 方法属于类,不属于对象,继承和重写是对象的行为,依赖运行时多态。但 static 方法在编译时就确定调用哪个类的方法,跟对象无关,所以不能被重写,也无法实现接口的抽象方法。而子类写同名 static 方法只是“隐藏”父类方法,不是真正的重写。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐