Java 中静态和非静态的区别

2025年6月23日 | 阅读 9 分钟

在 Java 中,静态(static)和非静态(non-static)成员在它们的存储、访问和使用方式上有所不同。

Java 中的静态成员

静态成员指的是类级别的变量或方法,这意味着它们属于类本身,而不是属于从类实例化的任何个别对象。这使得它们可以在类的所有实例之间共享资源。

  • 静态变量:这些变量使用 static 关键字声明,并且是类所有对象的公共变量。
  • 静态方法:这些方法可以在不创建类对象的情况下调用。它们只能直接访问静态数据。
  • 静态类:在 Java 中,静态类是使用 static 关键字声明的嵌套类。它与外部类相关联,而不是与外部类的实例相关联。

静态成员示例

示例

编译并运行

输出

解释

StaticInnerClass 是一个静态嵌套类,意味着无需 OuterClass 的实例即可访问它。staticVar 是一个静态变量,在所有实例之间共享。staticMethod() 是一个静态方法,可以使用类名调用。

Java 中的非静态成员

非静态成员是类每个实例独有的,因为它们与从类创建的对象相关联。

  • 非静态变量:每个对象都有自己的该变量副本。
  • 非静态方法:这些方法可以访问静态和非静态数据,并且需要对象才能调用。
  • 非静态类:非静态类是常规类,需要实例才能使用。与静态类不同,非静态类可以访问其包含类的静态和非静态成员。

非静态成员示例

示例

编译并运行

输出

Non-Static Method Called. Variable: 10

解释

NonStaticExample 是一个常规类,意味着需要实例才能使用。nonStaticVar 是一个非静态变量,对每个实例都是唯一的。nonStaticMethod() 是一个非静态方法,必须使用对象调用。

示例:静态和非静态成员

示例

编译并运行

输出

10
Static Method
20
Non-Static Method

静态成员和非静态成员之间的主要区别

1. 关联性

静态:静态成员(变量和方法)与类本身相关联,而不是与个别实例相关联。

非静态:非静态成员是类每个实例独有的,因为它们与从类创建的对象相关联。

2. 内存分配

静态:静态成员仅在类加载时分配一次内存。

非静态:非静态成员为类的每个实例分别分配内存。每个对象都有自己的非静态成员副本。

3. 访问

静态:静态成员可以直接使用类名后跟成员名(例如,ClassName.memberName)来访问。它们可以在程序中的任何位置访问。

System.out.println(Math.PI); // 访问 Math 类中的静态常量

非静态:非静态成员使用对象引用后跟成员名(例如,objectReference.memberName)来访问。它们是类特定实例的。

String s = new String("Java");

System.out.println(s.length()); // 使用对象访问非静态方法

4. 初始化

静态:静态成员在类加载到内存时进行初始化,通常在程序启动时。初始化只发生一次。

非静态:非静态成员在每次创建类实例时进行初始化,通常使用 new 关键字。每个对象都独立进行初始化。

5. 作用域

静态:静态成员具有全局作用域,可以在程序中的任何位置访问,即使没有创建类的实例。

非静态:非静态成员具有局部作用域,只能通过类的实例访问。没有对象就无法访问。

6. 访问成员

静态:静态成员只能直接访问同一类中的其他静态成员。它们不能直接访问非静态成员。

非静态:非静态成员可以访问同一类中的静态和非静态成员。它们可以直接访问所有成员。

7. 用途

静态:静态成员通常用于实用方法、常量或不属于特定实例的变量。例如,一个包含数学函数的 Math 类。

非静态:非静态成员用于实例特定的行为,因为它们保存每个对象的数据。例如,存储每个对象唯一值的实例变量。

8. 内存效率

静态:无论创建多少个实例,静态成员都只占用一次内存。当必须在所有对象之间共享相同数据时,它们可以节省内存。

非静态:非静态成员会消耗更多内存,因为每个对象都带有自己的副本。

9. 对象依赖性

静态:静态成员独立于对象;它们属于类,不与任何特定实例绑定。

非静态:非静态成员完全依赖于对象,并且它们的状态因对象而异。

10. 继承行为

静态:静态成员会被子类继承,但不能以传统意义上被覆盖。

非静态:非静态成员可以被继承,也可以被覆盖,以便在子类中提供自定义行为。

11. 同步

静态:静态方法可以在类级别进行同步,并且也会影响同时访问它们的所有线程。

非静态:非静态方法可以针对每个对象进行同步,从而对线程访问对象数据进行精细控制。

12. 覆盖和隐藏

静态:静态方法是方法隐藏(hiding)而不是方法重写(overriding)的对象。这是因为它们是在编译时绑定的,而不是在运行时。

非静态:非静态方法通过方法重写支持真正的运行时多态。

13. 引用

静态:可以直接通过类名引用静态成员,无需创建对象。

非静态:必须通过对象引用来引用非静态成员,否则会发生编译错误。

14. 序列化影响

静态:序列化对象时不会序列化静态变量,因为它们属于类,而不是对象。

非静态:非静态变量会被序列化,因为它们是对象当前状态的一部分。

15. 最佳实践用法

静态:当行为对于所有实例来说是通用且相同的,例如实用方法(Collections.sort())时,应使用静态成员。

非静态:当需要每个对象都有不同行为/数据时,应使用非静态成员,例如 Employee 的薪水或 Student 的分数。

16. 修改影响

静态:更改静态成员的值会影响所有对象,因为它们共享相同的内存地址。

非静态:更改非静态成员的值只会影响该特定对象。

17. 执行顺序

静态:静态块在类加载时首先执行,甚至在构造函数或任何对象创建之前。

非静态:非静态块和变量在创建每个新对象时进行初始化,位于静态块之后。

18. 现实生活中的例子

静态:将静态成员视为国家法律——它们对每个人都通用,无论您住在哪个城市。

非静态:非静态成员就像当地的城市规定——它们根据地点(或对象)而变化。

19. 接口中的支持

静态:Java 8 及更高版本允许在接口中使用静态方法,但实现类无法覆盖它们。

非静态:非静态方法(抽象方法)是接口中传统的需要类实现的方法。

20. 对设计模式的影响

静态:静态方法常用于单例(Singleton)、工具类(Utility classes)和工厂方法(Factory methods)等模式,以实现全局访问。

非静态:非静态成员广泛用于面向对象设计模式,如策略模式(Strategy)、观察者模式(Observer)和装饰器模式(Decorator),这些模式中对象的状态很重要。

下表总结了上述主要区别。

方面静态成员非静态成员
关联 (Association)与类本身相关。与每个对象实例相关。
内存分配在类加载时分配一次内存。为每个对象单独分配内存。
访问方式使用 ClassName.memberName 访问。使用 objectReference.memberName 访问。
初始化在类加载时初始化一次。每次创建对象时初始化。
范围全局作用域,可从任何地方访问。对象局部,需要实例。
成员访问只能访问其他静态成员。可以访问静态和非静态成员。
用途用于工具方法、常量。用于实例特定数据和行为。
内存效率对于共享数据,内存效率高。消耗更多内存(每个对象都有副本)。
生命周期只要类被加载就存在。只要对象存在就存在。
对象依赖性独立于对象。依赖于对象。
继承行为继承,但可以隐藏,不能重写。继承并可以正确重写。
同步支持类级别同步。支持对象级别同步。
重写和隐藏静态方法是隐藏的,不是重写的。非静态方法可以重写。
引用直接通过类名引用。必须通过对象名引用。
序列化影响对象序列化时不包含。作为对象状态的一部分进行序列化。
最佳实践用法最适合全局常量、实用工具。最适合实例行为和状态。
修改影响更改会影响所有实例。更改只会影响特定对象。
执行顺序类加载时先执行静态块。对象创建时执行非静态块。
存储位置存储在方法区。存储在堆内存。
绑定时间早期绑定(编译时)。晚期绑定(运行时)。
现实生活类比如国家规则(对所有人通用)。如地方规则(因地点/对象而异)。
接口中的支持Java 8+ 允许,但不能重写。传统的抽象方法必须实现。
性能访问速度更快(类级别)。由于对象查找,速度稍慢。
对设计模式的影响用于单例、工具类、工厂模式。用于策略、观察者和装饰器模式。
垃圾回收仅当类被卸载时回收。当对象变得不可达时回收。

Java 静态和非静态选择题

1. 如果我们尝试从静态上下文访问非静态方法会发生什么?

  1. 它将编译并运行
  2. 它将抛出运行时异常
  3. 它将无法编译
  4. 它将自动转换为静态
 

答案:c)

解释:静态上下文(如 main 方法)不能直接访问非静态成员,因为非静态成员需要类的实例。


2. 以下哪些可以声明为 static?

  1. 局部变量
  2. 方法
  3. 构造函数
  4. 对象
 

答案:b)

解释:方法和变量可以声明为 static。构造函数和局部变量不能声明为 static。


3. 关于 Java 中的静态方法,以下哪项是正确的?

  1. 它们属于类的实例
  2. 它们可以直接访问实例变量
  3. 它们可以使用 this 关键字
  4. 它们可以在不创建对象的情况下调用
 

答案: d)

解释:静态方法属于类,而不是任何对象。因此,可以使用类名在不创建实例的情况下调用它们。它们不能使用 this,因为 this 指的是当前对象,而在静态上下文中不存在。


4. 关于静态变量,以下哪个陈述是正确的?

  1. 它们只能在同一方法内访问
  2. 每个对象都有自己的副本
  3. 每次创建对象时都会初始化它们
  4. 它们在类的所有实例之间共享
 

答案: a)

解释:静态变量是类级别的变量,意味着类的所有实例都共享该变量的相同内存位置。


5. 在静态上下文中不允许什么?

  1. 调用另一个静态方法
  2. 访问静态变量
  3. 创建对象
  4. 使用 this 关键字
 

答案: d)

解释:this 指的是当前对象,在静态上下文中不存在。