Java static 关键字

2025年5月16日 | 阅读 12 分钟

Java 中的 static 关键字主要用于内存管理。我们可以将 static 关键字应用于变量、方法、代码块和嵌套类。static 关键字属于类,而不是类的实例。

static 可以是

  1. 变量(也称为类变量)
  2. 方法(也称为类方法)
  3. 嵌套类
Static in Java

除了内存管理,Java 中的 static 关键字还有其他几种用途。对于变量,它意味着类的所有实例共享该变量,并且该变量属于整个类,而不仅仅是任何一个实例。

静态方法在整个程序中都可用,因为它们可以在不首先创建类实例的情况下被调用。当类加载时,静态块用于初始化静态变量或执行一次性操作。

此外,嵌套的静态类可以单独实例化,但仍然与外部类相关联。而且,可以使用类名直接访问静态变量和方法,从而无需创建对象实例。这对于常量或实用方法特别有用。

static 关键字的特性

  1. 属于类,而非对象: 任何标记为 static 的成员都与类本身绑定,而不是与单个对象绑定。这意味着所有对象共享相同的静态变量和方法。
  2. 无需对象即可访问: 由于静态成员属于类,你可以直接使用类名(ClassName.methodName())来访问它们。无需创建对象。
  3. 静态方法不能直接使用实例变量: 静态方法不知道特定的对象,因此不能直接访问非静态(实例)变量或方法。
  4. main 方法是静态的: Java 中的 main 方法是静态的,这样 Java 就可以在不先创建对象的情况下运行程序。
  5. 在类加载时执行一次: 静态块在类首次加载时运行一次,这对于初始化常量等很有用。
  6. 不像普通方法那样被重写: 静态方法不遵循典型的方法重写规则。如果子类定义了相同的静态方法,这更像是重新声明它,而不是重写它。

1) Java 静态变量

如果我们将任何变量声明为 static,它就被称为静态变量。

  • 静态变量可用于引用所有对象的共同属性(对于每个对象来说不是唯一的),例如,员工的公司名称、学生的大学名称等。
  • 静态变量在类加载时,只在类区域中获取一次内存。
  • Java 中的静态变量如果没有被程序员显式初始化,也会被初始化为默认值。它们可以使用类名直接访问,无需创建类的实例。
  • 静态变量在类的所有实例之间共享,这意味着如果在一个实例中更改了静态变量的值,这个变化也会反映在所有其他实例中。

静态变量示例

示例

编译并运行

输出

111 Karan ITS
222 Aryan ITS

说明

这个 Java 程序演示了静态变量的用法。Student 类除了一个名为 college 的静态变量外,还定义了两个实例变量:rollno 和 name。它有一个构造函数用于设置实例变量的初始值,以及一个 display() 函数用于输出 rollno、name 和 college 的值。

TestStaticVariable1 类创建了两个 Student 对象 s1 和 s2,它们具有不同的学号和姓名。之后,调用每个对象的 display() 方法来打印其详细信息。通过取消注释 Student.college="BBDIT" 这一行,可以一次性为所有对象修改 college 名称,这展示了静态变量是如何被一个类的所有实例共享的。

Static in Java

不使用静态变量的计数器程序

在这个例子中,我们创建了一个名为 count 的实例变量,它在构造函数中递增。由于实例变量在创建对象时获取内存,每个对象都会有实例变量的一个副本。如果它被递增,不会影响其他对象。所以每个对象的 count 变量值都将是 1。

示例

编译并运行

输出

1
1
1

说明

这个 Java 程序演示了实例变量的概念,即每个从类派生的对象都具有其特定的实例变量。Counter 类中的 count 变量是一个实例变量,每次实例化该类的对象时都会分配内存。它被初始化为零。

每次创建对象时,构造函数都会打印 count 变量的当前值并将其递增。在 main 方法中,生成了三个 Counter 对象(c1、c2 和 c3),它们带有 count 变量的独立实例。因此,每次创建对象时,count 都会独立递增,输出显示了每个对象依次增加的 count 值。

使用静态变量的计数器程序

正如我们上面提到的,静态变量只会获得一次内存;如果一个对象改变了静态变量的值,它将保留其值。

示例

编译并运行

输出

1
2
3

说明

这个 Java 程序演示了静态变量的用法,该变量在从该类创建的所有对象之间共享。在 Counter2 类中,count 变量被声明为 static,确保它只分配一次内存,并在该类的所有实例中保持其值。

每次创建类的对象时,构造函数都会递增静态变量 count 的值并打印其当前值。在 main 方法中,实例化了三个 Counter2 对象(c1、c2 和 c3),由于它们共享相同的静态变量 count,其值会在这些对象之间顺序递增,反映了静态变量在类的所有实例中共享的特性。

2) Java 静态方法

如果我们将 static 关键字应用于任何方法,它就被称为静态方法。

  • 静态方法属于类,而不是类的对象。
  • 静态方法可以在不需要创建类实例的情况下被调用。
  • 静态方法可以访问静态数据成员并可以改变它们的值。

示例

编译并运行

输出

111 Karan BBDIT
       222 Aryan BBDIT
       333 Sonoo BBDIT

这个 Java 程序演示了如何在类内部使用静态方法。除了一个名为 college 的静态变量外,Student 类还定义了两个实例变量:rollno 和 name。它有一个名为 change() 的静态函数,用于修改静态变量 college 的值。

此外,该类还有一个用于初始化实例变量的构造函数和一个用于打印 rollno、name 和 college 值的 display() 方法。TestStaticMethod 类的 main 方法展示了如何使用 change() 方法来修改 college 的值。

之后,创建了三个具有不同学号和姓名的 Student 对象(s1、s2 和 s3),并使用 display() 方法显示了它们的详细信息。这说明了静态方法 change() 如何影响该类所有实例的静态变量 college。

让我们看另一个执行普通计算的静态方法示例。

示例

编译并运行

输出

125

说明

这个 Java 程序展示了如何使用静态函数计算给定数字的立方。Calculate 类中的静态方法 cube(int x) 将一个整数参数 x 乘以三次,返回其立方值。

同一个类的 main 方法演示了如何使用类名 Calculate 直接访问静态方法 cube(),而无需先创建该类的实例。

在这个例子中,cube() 方法以参数 5 被调用,结果保存在变量 result 中,然后打印到控制台。这个程序演示了使用静态方法进行常规计算或不需要创建对象的操作是多么简单和有效。

静态方法的限制

静态方法有以下两个主要限制。

  1. 静态方法不能直接使用非静态数据成员或直接调用非静态方法。
  2. this 和 super 关键字不能在静态上下文中使用。

文件名: A.java

输出

Compile Time Error

说明

提供的 Java 代码包含一个名为 A 的类。在类 A 中,有一个被指定为非静态的实例变量 a,其值为 40。然而,在类 A 的 main() 方法中,尝试使用 System.out.println(a); 直接访问实例变量 a。

由于 Java 中的静态方法不能直接访问非静态变量,这将导致编译问题。为了在静态的 main() 方法内访问非静态变量,必须首先创建类 A 的一个实例。然后,可以使用该实例来访问变量 a。因此,在 main 方法中使用 A obj = new A(); System.out.println(obj.a); 来访问 a 将是正确的。

问) 为什么 Java 的 main() 方法是静态的?

答) 在 Java 中,main() 方法是静态的,因为调用静态方法不需要对象。如果它是一个非静态方法,JVM 将首先创建一个对象,然后调用 main() 方法,这将导致额外的内存分配问题。

3) Java 静态块

  • 它用于初始化静态数据成员。
  • 它在类加载时,在 main() 方法之前执行。

示例

编译并运行

输出

static block is invoked
main() method is invoked

说明

在给定的 Java 代码中,有一个名为 A2 的类。在这个类内部,有一个静态块,这是一个用花括号括起来并用 static 关键字标记的代码块。静态块只在类加载到内存时执行一次,在执行 main 方法或创建该类的任何对象之前。

在这种情况下,静态块包含语句 System.out.println("static block is invoked"),当类 A2 加载到内存时,它会在控制台打印消息 "static block is invoked"。

此外,类 A2 中还有一个 main() 方法,执行时会在控制台打印 "Hello main"。然而,由于 main 方法是程序的入口点,它需要被显式调用,通常由 Java 虚拟机 (JVM) 在执行程序时调用。

因此,当你运行该程序时,静态块首先执行,打印来自静态块的消息,然后是 main 方法的执行,在控制台打印 "Hello main"。

问) 我们可以在没有 main() 方法的情况下执行程序吗?

答) 不可以,其中一种方法是使用静态块,但这只在 JDK 1.6 及以前版本中可行。从 JDK 1.7 开始,不带 main() 方法执行 Java 类是不可能的。

文件名: A3.java

输出

static block is invoked
Since JDK 1.7 and above, output would be:
Error: Main method not found in class A3, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

说明

所提供的 Java 代码中的 A3 类有一个静态块,它在向控制台打印 "static block is invoked" 后,使用 System.exit(0); 来终止程序。因此,当类加载到内存时,静态块运行,打印消息并立即停止程序,以阻止更多代码的运行。

4) 静态嵌套类

静态嵌套类使用 static 关键字声明。它的行为类似于一个常规的顶级类,但为了方便打包而被嵌套。静态嵌套类不能直接访问外部类的非静态成员。

注意:我们稍后会学习关于嵌套类的知识。

static 关键字的优点

  1. 节省内存: 静态变量在类的所有对象之间共享,而不是每个对象都拥有自己的一份变量副本。这节省了内存,因为只存在一份副本。
  2. 访问速度更快: 由于静态成员属于类本身,我们不需要创建对象来使用它们。我们可以直接使用类名调用它们,使你的代码运行得更快。
  3. 非常适合工具方法: 一些方法不依赖于对象数据,例如 Math.sqrt() 或 Integer.parseInt()。将它们标记为 static 允许我们直接使用它们而无需创建对象。
  4. 适用于常量: 如果一个值永不改变,例如 PI = 3.14159,将其设置为 static final 可以确保只有一个副本,从而使你的代码更高效。
  5. 保持代码组织性: 静态方法有助于将相关逻辑放在一个地方。例如,如果你有一个 DatabaseHelper 类,它的 connect() 和 disconnect() 方法可以是静态的,这样你就不必为了使用它们而创建一个对象。
  6. 在类加载时自动运行: 静态块在类加载时执行。这对于在程序开始前设置配置(如初始化数据库连接或加载文件)非常有用。
  7. 减少对象依赖: 静态方法不依赖于对象的状态,这使得它们在创建对象不必要或效率低下的情况下非常有用。

Java static 关键字 MCQ

1. 以下哪项不是 Java 中 static 关键字的有效用法?

  1. 声明静态方法
  2. 声明静态变量
  3. 将 static 应用于构造函数
  4. 声明静态嵌套类
 

答案:c)

解释: 在 Java 中,构造函数不能被声明为 static。static 关键字不适用于构造函数,因为它们本质上用于对象初始化,并在创建对象的上下文中被调用。


2. 在 Java 中使用静态变量的目的是什么?

  1. 存储特定于对象的数据
  2. 确保数据封装
  3. 维护一个由类的所有对象共享的公共属性
  4. 提供动态内存分配
 

答案:c)

解释: 静态变量在类的所有实例之间共享。它们只在程序执行开始时初始化一次,其值对该类的所有对象都是公共的。


3. 为什么 Java 中的 main 方法被声明为 static?

  1. 为了防止主类的实例化
  2. 为了允许 main 方法访问类的非静态成员
  3. 为了确保 main 方法可以在不创建类实例的情况下被调用
  4. 为了在程序执行期间提高内存效率
 

答案:c)

解释: 将 main 方法声明为 static 允许 Java 虚拟机 (JVM) 在无需实例化类的情况下调用它,从而方便程序的执行。


4. Java 中静态方法的一个关键限制是什么?

  1. 它们不能直接访问实例变量
  2. 它们不能在子类中被重写
  3. 它们不能在抽象类中声明
  4. 它们的返回类型不能是 void 以外的类型
 

答案:a)

解释: 静态方法属于类而不是单个对象,所以它们不能直接访问实例变量。它们只能访问类的其他静态成员。


5. 在 Java 中,静态块何时执行?

  1. 在每个静态方法执行之前
  2. 在 main 方法执行之后
  3. 在类的每个对象实例化期间
  4. 在类加载过程中,main 方法之前
 

答案:d)

解释: 静态块在类被 JVM 加载到内存时执行,通常在创建任何类的实例或调用任何方法之前。它们主要用于静态初始化任务。