今天写枚举类的时候发现了一个有趣的现象,在这里分享一下:
首先我们定义一个简单的枚举类:
/**
* @author jinghuaixin
* @date 2020/04/30
*/
public enum Week {
Monday, Tuesday;
// 静态代码块
static {
System.out.println("枚举中静态代码块执行了");
}
// 构造方法
private Week() {
System.out.println("枚举中构造方法执行了");
}
// 构造代码块
{
System.out.println("枚举中代码块执行了");
}
}
然后定义一个简单的测试类:
public class TestEnum {
static {
System.out.println("普通类中静态代码块执行了");
}
{
System.out.println("普通类中代码块执行了");
}
public TestEnum() {
System.out.println("普通类的构造方法执行了");
}
public static void main(String[] args) {
new TestEnum();
System.out.println("+++++++++++++++++++++++++++");
new TestEnum();
System.out.println("=========================");
Week week = Week.Monday;
System.out.println("=========================");
Week week2 = Week.Tuesday;
}
}
运行结果:
普通类中静态代码块执行了
普通类中代码块执行了
普通类的构造方法执行了
+++++++++++++++++++++++++++
普通类中代码块执行了
普通类的构造方法执行了
=========================
枚举中代码块执行了
枚举中构造方法执行了
枚举中代码块执行了
枚举中构造方法执行了
枚举中静态代码块执行了
=========================
普通类中,静态代码块在类加载的时候执行,类只会加载一次,所以只会执行一次,并且这个动作在对象实例化之前,所以是最先输出的,紧接着每次实例化都会去调用构造代码块和构造方法,所以会2次输出。但是枚举类就比较有趣了,可以看到枚举类中第一次使用的时候,调用构造代码块和构造方法块执行次数和枚举元素相等,第二次并没有再调用构造代码块和构造方法,静态代码块虽然也只执行了一次,但是却放在最后了,这是为什么呢?
我们借助jad反编译一下枚举类的代码:
jad Week.class
反编译生成的代码:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: Week.java
package learnbymaven.single;
import java.io.PrintStream;
public final class Week extends Enum
{
private Week(String s, int i)
{
super(s, i);
System.out.println("枚举中代码块执行了");
System.out.println("枚举中构造方法执行了");
}
public static Week[] values()
{
Week aweek[];
int i;
Week aweek1[];
System.arraycopy(aweek = ENUM$VALUES, 0, aweek1 = new Week[i = aweek.length], 0, i);
return aweek1;
}
public static Week valueOf(String s)
{
return (Week)Enum.valueOf(learnbymaven/single/Week, s);
}
public static final Week Monday;
public static final Week Tuesday;
private static final Week ENUM$VALUES[];
// 静态代码块初始化变量
static
{
Monday = new Week("Monday", 0);
Tuesday = new Week("Tuesday", 1);
ENUM$VALUES = (new Week[] {
Monday, Tuesday
});
System.out.println("枚举中静态代码块执行了");
}
}
通过反编译代码可以看到,枚举底层其实还是class,枚举元素是被声明成public static final的成员变量(可以通过类名直接调用),并且在static静态代码块中一起初始化了,这就解释了为什么第一次调用枚举类的时候,构造代码块和构造方法执行次数会和枚举元素相等,因为第一次加载类的时候就全部初始化了。由于java类的加载和初始化过程都是线程安全的,所以创建一个enum类型是线程安全的
一颗安安静静的小韭菜。文中如果有什么错误,欢迎指出。