对Java static关键字的理解总结。
static member/method
static修饰的成员或方法属于某个类而不是某个实例对象,该字段被所有实例共享。举个例子,在使用Unsafe实现对某个对象sizeOf的时候也是只需要判断非静态成员变量的offset即可。
static在这种场景下通常用于定义全局变量和通用的方法,可以节省内存开销。但是各个对象必然发生关联才能发挥功效,所以需要对象级别的属性和方法。
例子:
1 | public class StaticMemberMethod { |
static block
静态块是静态初始化器( Static Initializers),在类加载初始化的时候执行。和Static Initializers区别的是Instance Initializers, 也就是没有static修饰的块,实例初始化执行的时机是当一个实例创建的时候。不严谨的说法就是static block在我们的构造器执行之前运行,普通的block在我们的构造器执行之后,这句话是错误的!。这里需要理解类的初始化过程。
还有一个直观的理解就是,在static block里面不能访问实例变量(比如this.member),但是可以访问全局变量,传达的意思就是说现在只是类的加载过程,和实例的构造没有关系;而在non-static block里面就可以访问this.member,因为现在已经开始准备构建实例了。而且还要注意non-static block是在我们的构造器之前执行的。
例子:
1 | public class StaticBlock { |
输出:
1 | static block |
Spring中的一个使用场景:
1 | public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory |
Unsafe的实例化也是放在static block中。
1 | public final class Unsafe { |
static inner class
Java的内部类(也称嵌套类 nested class)分为静态内部类和(普通)内部类,non-static inner class可以访问外围类的所有成员,而static inner class没有外围类的引用,所以其不能访问非静态变量或调用非静态的成员方法。此外还要注意的是实例化这两种类的方式是不同的。
例子:
1 | public class OuterClass { |
关于内部类的使用场景也很多,如果HashMap中的Entry。还有一个常见的场景就是在initialization on demand holder单例实现中。
1 | public class Stage { |
总结:
- 动手实践
- 多看Oracle官方的文档
参考: