教程中心 / Java教程 / 静态成员

静态成员

10分钟 面向对象

什么是静态成员?

静态成员(Static Member)是Java中属于类而不是实例的成员。用static关键字修饰的字段或方法被所有对象共享,可以通过类名直接访问,无需创建对象。

生活比喻

想象一所学校。"学生姓名"是每个学生特有的(实例变量),但"学校名称"对所有学生都一样(静态变量)。无论多少学生,学校名称都只有一个,所有学生共享。静态成员就像学校公告板上的信息——属于整个学校,而不是某个学生。

实例成员 vs 静态成员:

实例成员(每个对象一份):
  对象1 ──► [name: 张三] [age: 20]
  对象2 ──► [name: 李四] [age: 22]
  
静态成员(所有对象共享一份):
  类 ──────────────────► [schoolName: 第一中学] ← 被所有对象共享
                       [studentCount: 2]

静态字段详解

静态字段(也叫类变量)在类加载时就创建,被类的所有实例共享。

public class Student {
    private String name;           // 实例变量 - 每个学生独有
    private static String schoolName = "第一中学";  // 静态变量 - 所有学生共享
    private static int studentCount = 0;  // 静态计数器

    public Student(String name) {
        this.name = name;
        studentCount++;  // 每创建学生,计数器+1
    }

    public void show() {
        System.out.println(name + " - 学校: " + schoolName);
    }

    // 静态方法访问静态变量
    public static int getStudentCount() {
        return studentCount;
    }
}

public class StaticFieldDemo {
    public static void main(String[] args) {
        // 通过类名访问静态变量
        System.out.println("学生总数: " + Student.getStudentCount());

        Student s1 = new Student("张三");
        System.out.println("添加后总数: " + Student.getStudentCount());

        Student s2 = new Student("李四");
        System.out.println("添加后总数: " + Student.getStudentCount());

        // 验证共享性
        System.out.println("\n===== 共享性验证 =====");
        System.out.println("修改前学校: " + Student.schoolName);
        Student.schoolName = "第二中学";  // 通过类名修改
        System.out.println("修改后学校: " + Student.schoolName);
        s1.show();  // 两个对象都显示新的学校名
        s2.show();
    }
}

静态方法详解

静态方法是属于类的方法,可以通过类名直接调用,但不能访问实例成员。

特性说明
调用方式类名.方法名(),无需创建对象
访问限制只能访问静态成员,不能访问实例成员
this/super不能使用,因为没有this指针
继承可被继承,但不能被重写(是隐藏不是覆盖)

常见错误:静态方法中访问实例变量

public class WrongExample {
    private int instanceVar = 10;  // 实例变量

    public static void main(String[] args) {
        // 错误!静态方法不能直接访问实例变量
        System.out.println(instanceVar);  // 编译错误!
    }
}

静态代码块

静态代码块在类加载时执行一次,用于初始化静态变量或执行一次性配置。

public class Config {
    private static String url;
    private static String apiKey;
    private static int timeout;

    // 静态代码块 - 类加载时执行一次
    static {
        System.out.println("Config类正在加载...");
        url = "https://api.example.com";
        apiKey = "sk-1234567890abcdef";
        timeout = 5000;
        // 可以执行更复杂的初始化逻辑
        validateConfig();
    }

    // 静态方法
    public static void showConfig() {
        System.out.println("===== 系统配置 =====");
        System.out.println("URL: " + url);
        System.out.println("API Key: " + apiKey.substring(0, 8) + "...");
        System.out.println("超时: " + timeout + "ms");
    }

    private static void validateConfig() {
        if (url == null || url.isEmpty()) {
            throw new IllegalStateException("URL不能为空");
        }
    }
}

public class StaticBlockDemo {
    public static void main(String[] args) {
        // 第一次访问Config类时会触发静态代码块
        Config.showConfig();
    }
}

静态初始化顺序

类加载时的初始化顺序:

1. 静态属性初始化
   ↓ 按声明顺序执行
2. 静态代码块执行
   ↓ 按出现顺序执行
3. 静态方法定义
   ↓ 只是方法定义,不自动执行
4. 静态方法被调用时
   ↓ 才执行方法体
5. 实例创建时
   ↓ 执行构造方法

静态内部类

用static修饰的内部类,不需要外部类实例即可创建。

public class Outer {
    private static int staticVar = 100;
    private int instanceVar = 200;

    // 静态内部类
    public static class StaticInner {
        public void show() {
            // 可以访问外部类的静态成员
            System.out.println("静态变量: " + staticVar);
            // 不能访问外部类的实例成员
            // System.out.println(instanceVar);  // 编译错误!
        }
    }

    // 非静态内部类
    public class Inner {
        public void show() {
            // 可以访问所有外部类成员
            System.out.println("静态: " + staticVar);
            System.out.println("实例: " + instanceVar);
        }
    }
}

public class StaticInnerDemo {
    public static void main(String[] args) {
        // 静态内部类:无需外部类实例
        Outer.StaticInner si = new Outer.StaticInner();
        si.show();

        // 非静态内部类:需要外部类实例
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.show();
    }
}

静态导包(Java 5+)

使用静态导包可以省略类名,直接使用静态成员。

import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
import static java.lang.System.out;

// 之后可以直接使用
public class StaticImportDemo {
    public static void main(String[] args) {
        double radius = 5.0;
        double area = PI * radius * radius;
        out.println("圆的面积: " + area);

        double hypotenuse = sqrt(3*3 + 4*4);
        out.println("直角三角形斜边: " + hypotenuse);
    }
}

静态的典型应用场景

1

工具类方法

如Math类的方法,都是静态的,不需要创建Math对象

double result = Math.sqrt(16);  // Math是工具类
2

全局计数器/配置

所有对象共享的数据,如学生总数、系统配置

3

单例模式

静态字段存储唯一实例

4

工厂方法

静态工厂方法创建对象

List list = Arrays.asList("a", "b", "c");

常见错误和注意事项

错误1:在静态方法中误用this

静态方法没有this指针,不能使用this关键字。

错误2:静态方法不能被重写

子类中的同名静态方法叫"隐藏",不是重写。通过父类引用调用时,执行的是父类的版本。

错误3:过度使用静态

静态变量在所有对象间共享,可能导致线程安全问题。并发环境下要谨慎使用。

小结

  • static成员属于类,所有对象共享
  • 静态字段在类加载时初始化,被所有对象共享
  • 静态方法只能访问静态成员,不能使用this
  • 静态代码块在类加载时执行一次,用于初始化
  • 静态内部类不需要外部类实例即可创建
  • 静态成员通过类名.成员名访问
☕ Java 在线代码编辑器
📝 运行结果