在本教程中,我们将详细探讨 Java 语言的 static 关键字。
我们将了解如何将 static 关键字应用于变量、方法、块和嵌套类,以及它有什么不同。
在 Java 编程语言中,关键字 static 意味着特定成员属于类型本身,而不是该类型的实例。
这意味着我们将只创建该static成员的一个实例,该实例在类的所有实例之间共享。
我们可以将static关键字应用于变量、方法、块和嵌套类。
在 Java 中,当我们声明一个字段是static的时,只会创建该字段的单个副本并在该类的所有实例之间共享。
我们实例化一个类多少次并不重要。始终只有一个属于它的static字段副本。此static字段的值在同一类的所有对象之间共享。
从内存的角度来看,static变量存储在堆内存中。
假设我们有一个具有多个属性(实例变量)的 Car 类。
每当我们从这个 Car 类实例化新对象时,每个新对象都会有其这些实例变量的不同副本。
但是,假设我们想要一个变量来保存实例化 Car 对象数量的计数,并在所有实例之间共享,以便它们可以访问它并在初始化时递增它。
这就是static变量的用武之地:
public class Car {
private String name;
private String engine;
public static int numberOfCars;
public Car(String name, String engine) {
this.name = name;
this.engine = engine;
numberOfCars++;
}
// getters and setters
}
现在,对于我们实例化的此类的每个对象,都会递增 numberOfCars 变量的相同副本。
因此,对于这种情况,这些将是真的:
@Test
public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() {
new Car("Jaguar", "V8");
new Car("Bugatti", "W16");
assertEquals(2, Car.numberOfCars);
}
以下是我们想要使用static字段的一些原因:
由于static变量属于一个类,我们可以使用类名直接访问它们。因此,我们不需要任何对象引用。
我们只能在类级别声明static变量。
我们可以在没有对象初始化的情况下访问static字段。
最后,我们可以使用对象引用(例如ford.numberOfCars++)访问static字段。但是我们应该避免这种情况,因为很难弄清楚它是实例变量还是类变量。相反,我们应该始终使用类名(Car.numberOfCars++)引用static变量。
与static字段类似,static方法也属于类而不是对象。因此,我们可以在不创建它们所在的类的对象的情况下调用它们。
我们通常使用static方法来执行不依赖于实例创建的操作。
为了在该类的所有实例之间共享代码,我们用static方法编写它:
static void setNumberOfCars(int numberOfCars) {
Car.numberOfCars = numberOfCars;
}
我们还通常使用static方法来创建实用程序或帮助程序类,以便我们可以在不创建这些类的新对象的情况下获取它们。
例如,我们可以查看JDK的Collections或Math实用程序类,Apache的StringUtils或Spring框架的CollectionUtils,并注意到它们的所有实用程序都是static的。
让我们看一下为什么我们要使用static方法的几个原因:
Java 中的static方法在编译时解析。由于方法重写是运行时多态性的一部分,因此无法重写static方法。
抽象方法不能是static的。
static方法不能使用此关键字或超级关键字。
实例、类方法和变量的以下组合有效:
我们使用static块来初始化static变量。虽然我们可以在声明期间直接初始化static变量,但在某些情况下我们需要进行多行处理。在这种情况下,static块会派上用场。
如果static变量在初始化期间需要额外的多语句逻辑,我们可以使用static块。
例如,假设我们想用一些预定义的值初始化一个 List 对象。
使用static块,这变得很容易:
public class StaticBlockDemo {
public static List<String> ranks = new LinkedList<>();
static {
ranks.add("Lieutenant");
ranks.add("Captain");
ranks.add("Major");
}
static {
ranks.add("Colonel");
ranks.add("General");
}
}
不可能使用所有初始值和声明初始化 List 对象。所以,这就是我们在这里使用static块的原因。
以下是使用static块的几个原因:
一个类可以有多个static块。
static字段和static块的解析和运行顺序与它们在类中存在的顺序相同。
Java允许我们在类中创建一个类。它提供了一种对元素进行分组的方法,我们只会在一个地方使用。这有助于使我们的代码更有条理和可读性。
通常,嵌套类体系结构分为两种类型:
这两者之间的主要区别在于,内部类可以访问封闭类的所有成员(包括私有成员),而static嵌套类只能访问外部类的static成员。
事实上,static嵌套类的行为与任何其他顶级类完全相同,但包含在将访问它的唯一类中,以提供更好的打包便利性。
创建单例对象的最广泛使用的方法是通过static嵌套类:
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
我们使用此方法是因为它不需要任何同步,并且易于学习和实现。
让我们看一下在代码中使用static内部类的几个原因:
基本上,static嵌套类无法访问封闭外部类的任何实例成员。它只能通过对象的引用访问它们。
static嵌套类可以访问封闭类的所有static成员,包括私有成员。
Java 编程规范不允许我们将顶级类声明为static。只有类中的类(嵌套类)才能设置为static。
通常,当我们在static上下文中使用非static变量时,会发生此错误。
正如我们之前看到的,static变量属于类,并在类加载时加载。另一方面,我们需要创建一个对象来引用非static变量。
因此,Java 编译器抱怨是因为需要对象调用或使用非static变量。
现在我们知道了导致错误的原因,让我们用一个例子来说明它:
public class MyClass {
int instanceVariable = 0;
public static void staticMethod() {
System.out.println(instanceVariable);
}
public static void main(String[] args) {
MyClass.staticMethod();
}
}
正如我们所看到的,我们在static方法staticMethod中使用了实例变量,这是一个非static变量。
结果,我们将收到错误非static变量无法从static上下文引用。
在本文中,我们看到了 static 关键字的实际应用。
我们还讨论了使用static字段、static方法、static块和static内部类的原因和优势。
最后,我们了解了导致编译器失败并显示错误“无法从static上下文引用非static变量”的原因。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有