Java关键字 - static

概念

在Java中,我们可以通过用static来表示某个字段或者方法为“全局“或者”静态“的意思,当然static也可以修饰代码块。

怎么使用static

static可以用于修饰成员变量和成员方法,我们将其称为静态变量和静态方法,可以直接通过类名进行访问。如下所示:

  • ClassName.propertyName
  • ClassName.methodName()

static修饰的代码块也称之为静态代码块,当其所属的类被加载时,就会优先先执行这部分代码。

static变量

static修饰的变量称之为静态变量,而没有static修饰的变量称之为实例变量。两者的区别在于:

静态变量是随着类加载时被完成初始化的,它在内存中仅有一个,且JVM也只会为它分配一次内存,同时类所有的实例都共享静态变量,可以直接通过类名来访问。

但是实例变量则不同,他是伴随着实例的创建而创建,也伴随着实例的消亡而消亡。而且实例变量只能够通过对象进行访问。

static函数

static修饰的方法称之为静态方法,可以直接通过类名对其进行调用。正因为static修饰的函数在类加载的时候就已经存在了,它不依赖于任何实例,所以static方法必须被实现,也就是说它不能够同时与abstract搭配修饰函数。

static方法是类中的一种特殊方法,当我们需要这个类下的某个方法完成某个特定的目的而无须将其实例化时,才将这个方法修饰为static。如Math类下的所有方法都是静态static的。

static代码块

static修饰的代码块称之为静态代码块,它会随着类加载的时候一块执行。静态代码块可以放置类中任意地方,且在类加载时,静态代码块按从下到上的顺序依次执行。

使用注意

static修饰的方法不能够调用非static变量或者非static方法

static所修饰的方法是从属于类的,且被由该类实例化出的所有对象所共享。若在static方法中调用了非static变量或非static方法,那么在运行期间,程序则无法确定此时的所调用的非static变量的确切值(因为成员变量的实际值取决于其所属的对象),从而导致程序运行错误。

静态代码块与非静态代码块的初始化顺序

优先级结论:静态代码块 == 静态变量初始化 > 实例代码块 == 实例变量初始化 > 实例构造器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package util_test;

public class Main {
{
System.out.println("main instance block");
}

static {
System.out.println("main static block");
}

public Main() {
System.out.println("main instance constructor");
}

public static void main(String[] args) {
new Son();
}
}

class Father {
{
System.out.println("father instance block");
}

static{
System.out.println("father static block");
}

public Father() {
System.out.println("father instance constructor");
}
}

class Son extends Father {
{
System.out.println("son instance block");
}

static {
System.out.println("son static block");
}

public Son() {
System.out.println("son instance constructor");
}
}

正确的执行顺序如下所示:

1
2
3
4
5
6
7
main static block
father static block
son static block
father instance block
father instance constructor
son instance block
son instance constructor

分析上述的代码加载过程。

  1. 因为main方法在Main类中,所以首先加载Main类,因此会执行Main类中的static代码块。接着执行main方法中的new Son()语句,而此时Son类尚未被加载,因此此时需要加载Son类。在加载Son类的时候,发现Son类是继承自Father类,所以转而去优先加载Father类,所以Father类中的static代码块会被执行,然后再执行Son类中的static代码块。
  2. 在所有所需的类加载完毕后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量以及执行实例代码块。因此先执行Father类中的实例代码块与构造器,最后再执行Son类中实例代码块与构造器。

参考资料

Java中的static关键字解析

java提高篇(七)—–关键字static