Java——static关键字
一、static关键字的基本概念
static是Java中一个重要的修饰符,用于修饰类中的成员。当成员被声明为static时,它就不再属于某个特定的对象实例,而是属于类本身,被所有对象实例共享。
特点:
静态成员在类加载时就被初始化
静态成员可以直接通过类名访问,无需创建对象
静态成员在内存中只有一份拷贝,被所有实例共享
二、修饰范围
1、成员变量(类变量)
- 特点:所有对象共享同一份数据
- 应用场景:计数器、全局配置参数
2、成员方法(类方法)
特点:不能直接访问非静态成员
应用场景:工具类方法(如Math.random())
3、代码块(静态代码块)
特点:类加载时自动执行一次
应用场景:加载配置文件、注册驱动
4、内部类(静态内部类)
特点:不依赖外部类实例
应用场景:Builder模式、工具类
// 类变量
public static int count;
// 类方法
public static void printCount() {...}
// 代码块
static {// 初始化静态资源
}
// 内部类
static class InnerClass {...}
三、内存机制
1、加载时机
类第一次被主动使用时完成static域分配(仅一次)
主动使用包括:
创建实例(new)
反射调用
访问静态成员(类名.静态变量/方法)
初始化子类(会先初始化父类)
2、static变量的使用
静态变量(类变量)是类的所有对象共享的变量,无论创建多少对象,都只存在一份静态变量。
public class Employee {private static int count = 0; // 静态变量private String name;public Employee(String name) {this.name = name;count++; // 每创建一个Employee对象,count加1}public static int getCount() {return count;}
}
3、static方法的使用
静态方法(类方法)属于类而不属于任何对象实例,可以直接通过类名调用。
public class MathUtils {public static double calculateCircleArea(double radius) {return Math.PI * radius * radius;}public static int max(int a, int b) {return a > b ? a : b;}
}double area = MathUtils.calculateCircleArea(5.0);
int maxNum = MathUtils.max(10, 20);
注意事项:
静态方法只能直接访问静态成员
静态方法中不能使用this和super关键字
静态方法不能被重写(但可以隐藏)
4、static代码块
静态代码块在类加载时执行,且只执行一次,通常用于初始化静态变量。
public class DatabaseConnection {private static String url;private static String username;private static String password;static {// 读取配置文件初始化连接参数Properties props = new Properties();try {props.load(new FileInputStream("db.properties"));url = props.getProperty("db.url");username = props.getProperty("db.username");password = props.getProperty("db.password");} catch (IOException e) {e.printStackTrace();}}
}
四、应用场景
工具类:如Math、Collections等工具类中的方法通常都是静态的
常量定义:public static final组合定义常量
单例模式:通过静态方法获取单例对象
工厂方法:通过静态方法创建对象
主方法:public static void main(String[] args)是Java程序的入口
五、特性
1、直接访问
无需创建类名.成员访问
System.out.println(Math.PI);
2、访问限制
静态方法中可直接访问静态成员,访问实例化成员必须先建立对象
public static void demo() {// 正确:访问静态变量System.out.println(staticVar);// 错误:直接访问实例变量// System.out.println(instanceVar);// 正确:通过对象访问MyClass obj = new MyClass();System.out.println(obj.instanceVar);
}
3、方法重写特性
静态方法不能被重写,但可以被“隐藏”(子类定于同名静态方法)
class Parent {static void show() { System.out.println("Parent"); }
}class Child extends Parent {static void show() { System.out.println("Child"); } // 方法隐藏
}Parent p = new Child();
p.show(); // 输出"Parent"(静态方法不存在多态)
五、初始化执行顺序
单类初始化顺序:静态属性初始化 → 静态代码块 → 实例属性初始化 → 实例代码块 → 构造方法
示例:
class Demo {static int a = initStatic(); // 1int b = initInstance(); // 3static { System.out.println("静态块"); } // 2{ System.out.println("实例块"); } // 4Demo() { System.out.println("构造器"); } // 5
}
继承体系顺序:父类静态 → 子类静态 → 父类实例 → 父类构造 → 子类实例 → 子类构造
示例:
class Parent {static { System.out.println("Parent静态块"); }{ System.out.println("Parent实例块"); }Parent() { System.out.println("Parent构造器"); }
}class Child extends Parent {static { System.out.println("Child静态块"); }{ System.out.println("Child实例块"); }Child() { System.out.println("Child构造器"); }
}// 执行 new Child() 时输出顺序:
// Parent静态块 → Child静态块 → Parent实例块 → Parent构造器 → Child实例块 → Child构造器
特殊场景说明
静态变量与静态块:按代码书写顺序执行
多次实例化:静态部分只执行一次
接口中的static:JDK8开始支持静态方法(不能被子接口继承)
六、注意事项
过度使用static会导致代码难以测试和维护
静态方法不能被重写,但子类可以声明同名静态方法(方法隐藏)
静态成员的生命周期与类相同,从类加载到JVM开始,到JVM结束
静态方法中不能直接访问非静态成员,必须通过对象实例访问