zoukankan      html  css  js  c++  java
  • java枚举类是怎么初始化的,为什么说枚举类是线程安全的

    今天写枚举类的时候发现了一个有趣的现象,在这里分享一下:

    首先我们定义一个简单的枚举类:

    /**
     * @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类型是线程安全的

    一颗安安静静的小韭菜。文中如果有什么错误,欢迎指出。
  • 相关阅读:
    Hadoop2.0 HA集群搭建步骤
    了解何为DML、DDL、DCL
    搭建Hadoop平台(新手入门)
    周记1
    IT小小鸟
    Python中的函数修饰符
    python_类方法和静态方法
    Python的log模块日志写两遍的问题
    python——装饰器例子一个
    初识HIVE
  • 原文地址:https://www.cnblogs.com/c-Ajing/p/13448352.html
Copyright © 2011-2022 走看看