> 技术文档 > Java基础(十):关键字static详解

Java基础(十):关键字static详解

Java基础系列文章

Java基础(一):初识Java——发展历程、技术体系与JDK环境搭建

Java基础(二):八种基本数据类型详解

Java基础(三):逻辑运算符详解

Java基础(四):位运算符详解

Java基础(五):流程控制全解析——分支(if/switch)和循环(for/while)的深度指南

Java基础(六):数组全面解析

Java基础(七): 面向过程与面向对象、类与对象、成员变量与局部变量、值传递与引用传递、方法重载与方法重写

Java基础(八):封装、继承、多态与关键字this、super详解

Java基础(九):Object核心类深度剖析

Java基础(十):关键字static详解

目录

  • 一、static的基本概念
  • 二、static变量
    • 1、静态变量(类变量)
    • 2、静态变量的初始化
    • 3、静态变量 vs 实例变量
    • 4、静态变量的线程安全性
  • 三、static方法
    • 1、静态方法
    • 2、静态方法的使用限制
  • 四、static代码块
  • 五、static嵌套类
    • 1、静态内部类
    • 2、常见用途(Builder模式)
  • 六、静态导入

一、static的基本概念

  static是Java中的一个修饰符,可用于修饰类的成员变量方法代码块嵌套类。被static修饰的成员属于类本身,而不是类的某个实例对象。这意味着静态成员在类加载时就会被初始化,并且所有该类的实例共享同一份静态成员。

二、static变量

1、静态变量(类变量)

  • 静态变量属于类,而不是某个特定的对象实例。所有实例共享同一个静态变量
public class Counter { // 静态变量 private static int count = 0; public Counter() { count++; // 每次创建实例时count增加 } public static int getCount() { return count; }}// 使用示例public class Main { public static void main(String[] args) { Counter c1 = new Counter(); Counter c2 = new Counter(); Counter c3 = new Counter(); System.out.println(\"创建的实例数量: \" + Counter.getCount()); // 输出: 3 }}

2、静态变量的初始化

  • JVM加载类时,会执行类初始化​(Class Initialization),此时静态变量会被显式赋值(若未显式赋值则使用默认值)
    • 默认值规则​:数值类型为0,布尔类型为false,引用类型为null
    • 显式赋值​:在定义中直接赋值,或在静态代码块中赋值(二者执行顺序按代码编写顺序)
public class InitializationExample { // 声明时初始化 static int a = 10; // 静态代码块初始化 static int b; static { b = 20; } // 默认赋值 static int c; public static void main(String[] args) { System.out.println(\"a=\" + a); // 输出10 System.out.println(\"b=\" + b); // 输出20 System.out.println(\"c=\" + c); // 输出0 }}

3、静态变量 vs 实例变量

特性 静态变量 实例变量 内存分配 类加载时分配,在方法区 对象创建时分配,在堆内存 生命周期 与类相同 与对象实例相同 访问方式 类名.变量名 或 对象.变量名 只能通过对象.变量名 共享性 所有实例共享 每个实例独有

4、静态变量的线程安全性

  • 静态变量被所有实例共享,多线程环境下修改可能导致数据不一致(需通过synchronizedLockAtomicXXX类保证原子性)
public class ThreadSafeCounter { private static int count = 0; private static final Object lock = new Object(); // 线程不安全的递增 public static void unsafeIncrement() { count++; } // 线程安全的递增 public static void safeIncrement() { synchronized (lock) { count++; } } // 使用AtomicInteger实现线程安全 private static AtomicInteger atomicCount = new AtomicInteger(0); public static void atomicIncrement() { atomicCount.incrementAndGet(); }}

三、static方法

1、静态方法

  • 静态方法属于类,而不是类的实例
  • 可以通过类名直接调用,无需创建实例
public class MathUtils { // 静态变量 private static final double PI = 3.14159; // 静态方法 public static double calculateCircleArea(double radius) { return PI * radius * radius; } // 另一个静态方法,可以调用其他静态方法 public static double calculateCircleCircumference(double radius) { return 2 * PI * radius; }}// 使用示例public class Main { public static void main(String[] args) { double area = MathUtils.calculateCircleArea(5.0); double circumference = MathUtils.calculateCircleCircumference(5.0); System.out.println(\"面积: \" + area); System.out.println(\"周长: \" + circumference); }}

2、静态方法的使用限制

  1. 不能使用this和super关键字:因为静态方法不依赖于任何实例
  2. 不能直接访问实例变量和实例方法:只能直接访问静态成员
  3. 不能被重写:静态方法可以被子类\"隐藏\",但不能被重写

代码示例:重写 vs. 隐藏

  • 隐藏:​​ 针对静态方法、静态变量和实例变量
  • 发生在编译时,基于引用的声明类型(等号左边的类型)来决定调用哪个方法或字段
  • 这就是静态绑定或早期绑定
class Animal { // 这是一个静态方法,将被“隐藏” public static void staticMethod() { System.out.println(\"Animal: Static Method\"); } // 这是一个实例方法,将被“重写” public void instanceMethod() { System.out.println(\"Animal: Instance Method\"); }}class Dog extends Animal { // 隐藏父类的静态方法 (使用 @Override 注解会报错,因为它不是重写) public static void staticMethod() { System.out.println(\"Dog: Static Method\"); } // 重写父类的实例方法 (使用 @Override 注解是正确且推荐的) @Override public void instanceMethod() { System.out.println(\"Dog: Instance Method\"); }}public class Test { public static void main(String[] args) { // 关键:声明类型为 Animal,实际对象为 Dog Animal myAnimal = new Dog(); // 调用静态方法 - 隐藏 (看引用类型 Animal) myAnimal.staticMethod(); // 输出: Animal: Static Method // 调用实例方法 - 重写 (看对象类型 Dog) myAnimal.instanceMethod(); // 输出: Dog: Instance Method // 通过类名调用静态方法(正确方式) Animal.staticMethod(); // 输出: Animal: Static Method Dog.staticMethod(); // 输出: Dog: Static Method }}

四、static代码块

  • 静态代码块在类加载时执行,且只执行一次,常用于初始化静态变量或执行只需进行一次的操作
public class DatabaseConnection { private static Connection connection; // 静态代码块 static { try { // 初始化数据库连接 connection = DriverManager.getConnection(\"jdbc:mysql://localhost:3306/mydb\", \"user\", \"password\"); System.out.println(\"数据库连接已建立\"); } catch (SQLException e) { System.out.println(\"数据库连接失败: \" + e.getMessage()); } } public static Connection getConnection() { return connection; }}

五、static嵌套类

1、静态内部类

  • static嵌套类(静态内部类)是声明为static的内部类
    • 不依赖于外部类的实例
    • 可以访问外部类的static成员
    • 不能直接访问外部类的非static成员
    • 可以包含static和非static成员
public class OuterClass { private static String staticField = \"静态字段\"; private String instanceField = \"实例字段\"; // 静态嵌套类 public static class StaticNestedClass { public void print() { System.out.println(staticField); // 可以访问外部类的静态成员 // System.out.println(instanceField); // 错误:不能访问外部类的实例成员 } } // 内部类(非静态) public class InnerClass { public void print() { System.out.println(staticField); // 可以访问静态成员 System.out.println(instanceField); // 也可以访问实例成员 } }}// 使用示例public class Main { public static void main(String[] args) { // 依赖外部类,需要先创建外部类,再创建内部类实例 OuterClass outer = new OuterClass(); OuterClass.InnerClass inner = outer.new InnerClass(); inner.print(); // 不需要外部类实例,直接创建静态嵌套类实例 OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass(); nested.print(); }}

2、常见用途(Builder模式)

示例:自定义一个带有 Builder 模式的类

public class User {// 成员变量 private String name; private Integer age; private String email;// 私有构造方法,只能通过 Builder 构建 private User(String name, Integer age, String email) { this.name = name; this.age = age; this.email = email; } public static UserBuilder builder() { return new UserBuilder(); }// 静态内部类 Builder public static class UserBuilder { private String name; private Integer age; private String email; private UserBuilder() { }// 设置参数的方法,返回 Builder 本身,支持链式调用 public UserBuilder name(final String name) { this.name = name; return this; } public UserBuilder age(final Integer age) { this.age = age; return this; } public UserBuilder email(final String email) { this.email = email; return this; }// 构建 User 对象 public User build() { return new User(this.name, this.age, this.email); } }}

使用方式:

public class Main { public static void main(String[] args) { User user = User.builder() .name(\"xuchang\") .age(18) .email(\"xuchang@gmail.com\") .build(); System.out.println(user); }}

六、静态导入

  • Java 5引入了static导入功能,允许直接使用其他类中定义的static成员而不需要类名前缀
// 导入Math类的所有static成员import static java.lang.Math.*;public class StaticImportExample { public static void main(String[] args) { // 直接使用Math类的static方法,无需Math.前缀 double result = sin(PI / 2) + cos(0); System.out.println(\"计算结果: \" + result); // 输出2.0 }}
  • 也可以只导入特定的static成员
// 只导入Math类的sqrt和PIimport static java.lang.Math.sqrt;import static java.lang.Math.PI;public class SelectiveStaticImport { public static void main(String[] args) { double area = PI * sqrt(2) * sqrt(2); // 计算半径为√2的圆的面积 System.out.println(\"面积: \" + area); // 输出约6.283185307179586 }}