A Guide to the Static Keyword in Java – Java中的静态关键字指南

最后修改: 2017年 10月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll explore the static keyword of the Java language in detail.

在本教程中,我们将详细探讨Java语言的static关键字。

We’ll find out how we can apply the static keyword to variables, methods, blocks, and nested classes, and what difference it makes.

我们将找出如何将static关键字应用于变量、方法、块和嵌套类,以及它的区别。

2. The Anatomy of the static Keyword

2.静态关键词的解剖

In the Java programming language, the keyword static means that the particular member belongs to a type itself, rather than to an instance of that type.

在Java编程语言中,关键字static意味着特定成员属于一个类型本身,而不是该类型的实例。

This means we’ll create only one instance of that static member that’s shared across all instances of the class.

这意味着我们将只创建一个静态成员的实例,该实例在类的所有实例中共享。

Static variables shared in Java

We can apply the keyword to variables, methods, blocks, and nested classes.

我们可以将该关键字应用于变量、方法、块和嵌套类。

3. The static Fields (Or Class Variables)

3.静态字段(或类变量)

In Java, when we declare a field static, exactly a single copy of that field is created and shared among all instances of that class.

在Java中,当我们声明一个字段为static时,该字段正好有一个副本被创建并在该类的所有实例中共享。

It doesn’t matter how many times we instantiate a class. There will always be only one copy of static field belonging to it. The value of this static field is shared across all objects of either the same class.

我们对一个类进行多少次实例化并不重要。属于它的static字段永远只有一个副本。这个static字段的值在所有同一类的对象中共享。

From the memory perspective, static variables are stored in the heap memory.

从内存的角度来看,静态变量被存储在堆内存中。

3.1. Example of the static Field

3.1.静态字段的例子

Let’s say we have a Car class with several attributes (instance variables).

假设我们有一个汽车类,有几个属性(实例变量)

Whenever we instantiate new objects from this Car blueprint, each new object will have its distinct copy of these instance variables.

每当我们从这个Car蓝图中实例化新对象时,每个新对象都会有这些实例变量的独特副本。

However, suppose we want a variable that holds the count of the number of instantiated Car objects and is shared across all instances so they can access it and increment it upon their initialization.

然而,假设我们想要一个变量来保存实例化的Car对象的数量,并且在所有实例之间共享,这样它们就可以在初始化时访问它并增加它。

That’s where static variables come in:

这就是静态变量的作用。

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
}

Now for every object of this class that we instantiate, the same copy of the numberOfCars variable is incremented.

现在,对于我们实例化的这个类的每一个对象,numberOfCars变量的同一副本被递增。

So, for this case, these will be true:

因此,对于这种情况,这些将是真实的。

@Test
public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() {
    new Car("Jaguar", "V8");
    new Car("Bugatti", "W16");
 
    assertEquals(2, Car.numberOfCars);
}

3.2. Compelling Reasons to Use static Fields

3.2.使用静态字段的令人信服的理由

Here are some reasons for when we’d want to use static fields:

以下是我们想使用静态字段的一些原因。

  • when the value of the variable is independent of objects
  • when the value is supposed to be shared across all objects

3.3. Key Points to Remember

3.3.需要记住的关键点

Since static variables belong to a class, we can access them directly using the class name. So, we don’t need any object reference.

由于静态变量属于一个类,我们可以使用类的名称直接访问它们。所以,我们不需要任何对象引用。

We can only declare static variables at the class level.

我们只能在类一级声明静态变量。

We can access static fields without object initialization.

我们可以访问静态字段,而不需要对象初始化

Finally, we can access static fields using an object reference (such as ford.numberOfCars++). But we should avoid this because it becomes difficult to figure out if it’s an instance variable or a class variable. Instead, we should always refer to static variables using the class name (Car.numberOfCars++).

最后,我们可以使用对象引用来访问静态字段(比如ford.numberOfCars++)。但是我们应该避免这样做,因为这样就很难弄清楚它是一个实例变量还是一个类变量。相反,我们应该总是使用类名来引用静态变量(Car.numberOfCars++

4. The static Methods (Or Class Methods)

4.静态方法(或类方法)

Similar to static fields, static methods also belong to a class instead of an object. So, we can call them without creating the object of the class in which they reside.

static字段类似,static方法也属于一个类而不是一个对象。因此,我们可以在不创建它们所在的类的对象的情况下调用它们。

4.1. Example of static Method

4.1.静态方法的例子

We generally use static methods to perform an operation that’s not dependent upon instance creation.

我们通常使用static方法来执行一个不依赖于实例创建的操作。

In order to share code across all instances of that class, we write it in a static method:

为了在该类的所有实例中共享代码,我们把它写在一个静态方法中。

static void setNumberOfCars(int numberOfCars) {
    Car.numberOfCars = numberOfCars;
}

We also commonly use static methods to create utility or helper classes so that we can get them without creating a new object of these classes.

我们也通常使用static方法来创建实用类或辅助类,这样我们就可以在不创建这些类的新对象的情况下得到它们。

As examples, we can take a look at Collections or Math utility classes from JDK, StringUtils from Apache, or CollectionUtils from Spring framework and notice that all their utility methods are static.

作为例子,我们可以看看JDK的CollectionsMath实用类,Apache的StringUtils,或Spring框架的CollectionUtils,注意它们所有实用方法都是static

4.2. Compelling Reasons to Use static Methods

4.2.使用静态方法的令人信服的理由

Let’s look at a few reasons why we’d want to use static methods:

让我们来看看为什么我们要使用静态方法的几个原因。

  • to access/manipulate static variables and other static methods that don’t depend upon objects.
  • static methods are widely used in utility and helper classes.

4.3. Key Points to Remember

4.3.需要记住的关键点

static methods in Java are resolved at compile time. Since method overriding is part of Runtime Polymorphism, static methods can’t be overridden.

Java中的静态方法是在编译时解决的。由于方法重写是运行时多态性的一部分,静态方法不能被重写

Abstract methods can’t be static.

抽象方法不能是静态的。

static methods can’t use this or super keywords.

static方法不能使用thissuper关键字。

The following combinations of the instance, class methods, and variables are valid:

以下实例、类方法和变量的组合是有效的。

  1. instance methods can directly access both instance methods and instance variables
  2. instance methods can also access static variables and static methods directly
  3. static methods can access all static variables and other static methods
  4. static methods can’t access instance variables and instance methods directly. They need some object reference to do so.

5. A static Block

5.一个静态

We use a static block to initialize static variables. Although we can initialize static variables directly during declaration, there are situations when we need to do multiline processing. In such cases, static blocks come in handy.

我们使用一个static块来初始化static变量。尽管我们可以在声明时直接初始化static变量,但有些情况下我们需要进行多行处理。在这种情况下,static块就派上了用场。

If static variables require additional, multi-statement logic during initialization, we can use a static block.

如果静态变量在初始化过程中需要额外的、多语句逻辑,我们可以使用静态块。

5.1. The static Block Example

5.1.静态块示例

For instance, let’s suppose we want to initialize a List object with some predefined values.

例如,让我们假设我们想用一些预定义的值来初始化一个List对象。

This becomes easy with static blocks:

有了静态块,这就变得容易了。

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");
    }
}

It wouldn’t be possible to initialize a List object with all the initial values along with declaration. So, this is why we’ve utilized the static block here.

我们不可能用所有的初始值和声明来初始化一个List对象。所以,这就是为什么我们在这里利用了static块。

5.2. Compelling Reasons to Use static Blocks

5.2.使用静态块的令人信服的理由

Below are a few reasons for for using static blocks:

以下是使用静态块的几个原因。

  • if the initialization of static variables needs some additional logic apart from the assignment
  • if the initialization of static variables is error-prone and needs exception handling

5.3. Key Points to Remember

5.3.需要记住的关键点

A class can have multiple static blocks.

一个类可以有多个静态

static fields and static blocks are resolved and run in the same order as they are present in the class.

static字段和static块被解析,并按照它们在类中存在的相同顺序运行。

6. A static Class

6.一个静态

Java allows us to create a class within a class. It provides a way of grouping elements that we’ll only use in one place. This helps to keep our code more organized and readable.

Java允许我们在一个类中创建一个类。它提供了一种将我们只在一个地方使用的元素分组的方法。这有助于保持我们的代码更有组织性和可读性。

In general, the nested class architecture is divided into two types:

一般来说,嵌套类架构分为两种类型。

  • nested classes that we declare static are called static nested classes
  • nested classes that are non-static are called inner classes

The main difference between these two is that the inner classes have access to all members of the enclosing class (including private ones), whereas the static nested classes only have access to static members of the outer class.

这两者之间的主要区别是,内层类可以访问外层类的所有成员(包括private ones),而static 嵌套类只能访问外层类的静态成员。

In fact, static nested classes behave exactly like any other top-level class, but are enclosed in the only class that will access it, to provide better packaging convenience.

事实上,静态嵌套类的行为与其他顶层类完全一样,但被包围在唯一会访问它的类中,以提供更好的打包便利。

6.1. Example of static Class

6.1.静态类的例子

The most widely used approach to create singleton objects is through a static nested class:

创建单子对象最广泛使用的方法是通过static嵌套类。

public class Singleton  {
    private Singleton() {}

    private static class SingletonHolder {
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

We use this method because it doesn’t require any synchronization and is easy to learn and implement.

我们使用这种方法是因为它不需要任何同步,而且很容易学习和实现。

6.2. Compelling Reasons to Use a static Inner Class

6.2.使用静态内类的令人信服的理由

Let’s take a look at a few reasons for using static inner classes in our code:

让我们来看看在我们的代码中使用静态内类的几个原因。

  • grouping classes that will be used only in one place increases encapsulation
  • we bring the code closer to the only place that will use it. This increases readability, and the code is more maintainable.
  • if a nested class doesn’t require any access to its enclosing class instance members, it’s better to declare it as static. This way, it won’t be coupled to the outer class and is therefore more optimal, as they won’t require any heap or stack memory.

6.3. Key Points to Remember

6.3.需要记住的关键点

Basically, a static nested class doesn’t have access to any instance members of the enclosing outer class. It can only access them through an object’s reference.

基本上,一个静态嵌套类不能访问任何包围的外层类的实例成员。它只能通过一个对象的引用来访问它们。

static nested classes can access all static members of the enclosing class, including private ones.

静态嵌套类可以访问包围类的所有静态成员,包括私有成员。

Java programming specification doesn’t allow us to declare the top-level class as static. Only classes within the classes (nested classes) can be made as static.

Java编程规范不允许我们将顶级类声明为static。只有类中的类(嵌套类)才可以被作为static

7. Understanding the Error “Non-static variable cannot be referenced from a static context”

7.理解错误”不能从静态环境中引用非静态变量”

Typically, this error occurs when we use a non-static variable inside a static context.

通常情况下,当我们在静态上下文中使用一个非静态变量时,会出现这种错误。

As we saw earlier, static variables belong to the class and are loaded at class load time. On the other hand, we need to create an object in order to refer to non-static variables.

正如我们前面看到的,静态变量属于类,在类加载时被加载。另一方面,我们需要创建一个对象,以便引用非静态变量。

So, the Java compiler complains because there’s a need for an object to call or use non-static variables.

因此,Java编译器会抱怨,因为有一个对象需要调用或使用非静态变量。

Now that we know what causes the error, let’s illustrate it using an example:

现在我们知道了错误的原因,让我们用一个例子来说明它。

public class MyClass { 
    int instanceVariable = 0; 
    
    public static void staticMethod() { 
        System.out.println(instanceVariable); 
    } 
    
    public static void main(String[] args) {
        MyClass.staticMethod();
    }
} 

As we can see, we used instanceVariable, which is a non-static variable, inside the static method staticMethod.

我们可以看到,我们在静态方法staticMethod中使用了instanceVariable,它是一个非静态变量。

As a result, we will get the error Non-static variable cannot be referenced from a static context.

结果,我们将得到错误非静态变量不能从静态上下文中引用

8. Conclusion

8.结论

In this article, we saw the static keyword in action.

在这篇文章中,我们看到了static关键字的作用。

We also discussed the reasons and advantages of using static fields, static methods, static blocks, and static inner classes.

我们还讨论了使用静态字段、静态方法、静态块和静态内类的原因和优势。

Finally, we learned what causes the compiler to fail with the error “Non-static variable cannot be referenced from a static context”.

最后,我们了解到是什么原因导致编译器出现”不能从静态上下文引用非静态变量 “的错误

As always, we can find the complete code over on GitHub.

一如既往,我们可以在GitHub上找到完整的代码超过