Java中enum的静态成员的初始化
<iframe id="I0_1381823279752" style="left: 0px; top: 0px; width: 106px; height: 24px; visibility: visible; position: static;" title="+1" name="I0_1381823279752" src="https://apis.google.com/_/+1/fastbutton?usegapi=1&bsv=o&hl=en-US&origin=http%3A%2F%2Fwww.wcode.net&url=http%3A%2F%2Fwww.wcode.net%2Fplus%2Fview.php%3Faid%3D391173&gsrc=3p&ic=1&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.zh_CN.lSYkxgKBWqM.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAItRSTNjoa6rd0Hi1Wa13BfCczyGvikJBA#_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart%2Concircled%2Cdrefresh%2Cerefresh&id=I0_1381823279752&parent=http%3A%2F%2Fwww.wcode.net&pfname=&rpctoken=28548003" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" width="100%" data-gapiattached="true"></iframe>
时间:2009-09-02 00:00来源: 作者:admin 点击: 67次
<!-- /info -->
Java语言规范第三版8.9规定了enum里的构造器、初始化器和初始化块中不得引用该enum中非编译时常量的静态成员域。 引用It is a compile-time error to reference a static field of an enum type that is not a compile-time constant (§15.28) from constructors, instance initializer blocks, or instance variable initial
Java语言规范第三版8.9规定了enum里的构造器、初始化器和初始化块中不得引用该enum中非编译时常量的静态成员域。 引用
It is a compile-time error to reference a static field of an enum type that is not a compile-time constant (§15.28) from constructors, instance initializer blocks, or instance variable initializer expressions of that type. It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant e to refer to itself or to an enum constant of the same type that is declared to the right of e.
规范特别指出构造器与初始化器禁止访问静态成员域是为了禁止一些循环初始化的状况。例子是: Java Language Specification, 3rd 写道
enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); Color() { colorMap.put(toString(), this); } } Java枚举类型中的枚举成员是静态成员,它们会首先被静态初始化;其它成员都只能在枚举成员之后声明,如果通过初始化器(如上例)来初始化的话,则开始初始化RED时静态变量colorMap尚未被赋值。 初始化RED时要调用Color的构造器。如果允许构造器访问colorMap,就会对null调用了put()方法,于是遇到NullPointerException。 规范认为添加了上述限制后就可以让这种循环初始化的代码无法编译,从而杜绝其造成运行时异常的问题。 今天突然想起我前段时间才见到别人问过enum的初始化问题,而且就是遇到了静态初始化失败的错误。问了几个同学都说没问过我,稍微搜了下JavaEye问答频道也没看到。我还会是在哪里看到的呢,怪哉。我肯定是RP了…… 想了会儿,总算构造出了记忆中见到的那种错误: import java.util.*; public class Demo { public static void main(String[] args) { PowerOfTwo i = PowerOfTwo.fromInt(2); System.out.println(i); } } enum PowerOfTwo { ONE(1), TWO(2), FOUR(4), EIGHT(8); private int value; PowerOfTwo(int value) { this.value = value; registerValue(); //map.put(value, this); } @Override public String toString() { return Integer.toString(this.value); } private void registerValue() { PowerOfTwo.map.put(value, this); } public static PowerOfTwo fromInt(int i) { return PowerOfTwo.map.get(i); } private static final Map<Integer, PowerOfTwo> map = new HashMap<Integer, PowerOfTwo>(); } 留意第17行,被注释掉的代码如果放进来就通不过编译,跟规范里提到的要避免的状况一样。但是把同样的逻辑放到了成员方法之后,我们就成功的看到了静态初始化错误: 引用
Exception in thread "main" java.lang.ExceptionInInitializerError
at Demo.main(Demo.java:5) Caused by: java.lang.NullPointerException at PowerOfTwo.registerValue(Demo.java:26) at PowerOfTwo.<init>(Demo.java:17) at PowerOfTwo.<clinit>(Demo.java:11) ... 1 more 留意调用栈的状况。“... 1 more”没有显示出来的那个是Demo.main。它调用了PowerOfTwo枚举类型上的静态方法,引发了该类型的静态初始化(PowerOfTwo.<clinit>);其中,RED成员首先被初始化,调用构造器(PowerOfTwo.<init>);构造器则调用了成员方法registerValue来添加映射信息,访问到尚未被初始化到HashMap实例的静态成员域map,然后就出错了。 也就是说上述限制的作用很有限……跟泛型有的一拼,呵呵。 知道了问题没关系,只要问题有解决的办法就行。规范中也提供了Color例子的正确写法: Java Language Specification, 3rd 写道
enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); static { for (Color c : Color.values()) colorMap.put(c.toString(), c); } } 关键点是在声明了静态成员域之后,在一个静态初始化块里来完成其内容的填充,而不要急着在构造器里就去做。当然要是在构造器里先判断一下null然后做合适的初始化也不是不行,但那样代码长了而且每构造一个实例都要检查一次,麻烦。原本需要针对每个实例做的初始化可以靠values()方法遍历所有的枚举成员来做。 回到PowerOfTwo的例子,那就是改成: import java.util.*; public class Demo { public static void main(String[] args) { PowerOfTwo i = PowerOfTwo.fromInt(2); System.out.println(i); } } enum PowerOfTwo { ONE(1), TWO(2), FOUR(4), EIGHT(8); private int value; PowerOfTwo(int value) { this.value = value; } @Override public String toString() { return Integer.toString(this.value); } public static PowerOfTwo fromInt(int i) { return PowerOfTwo.map.get(i); } private static Map<Integer, PowerOfTwo> map = new HashMap<Integer, PowerOfTwo>(); static { for (PowerOfTwo p : PowerOfTwo.values()) { PowerOfTwo.map.put(p.value, p); } } }
|
相关推荐
java中enum枚举的详细用法。 0.0
Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类...
主要介绍了java 中enum的使用方法详解的相关资料,希望通过本文能帮助到大家,理解掌握java 中enum的使用方法,需要的朋友可以参考下
Java enum的用法详解,可作为开发api
Java中的Enum的使用与分析
Java中enum的用法.pdf
博文“Java 语言中 Enum 类型的使用介绍”的源码。
java enum详细教程。由浅入深,包括基本语法方面..很适合新手学习。/n各位看官。绝对超值。
enum李兴华视频笔记,绝对值得看!
NULL 博文链接:https://rensanning.iteye.com/blog/2013734
主要介绍了Java Enum和String及int的相互转化示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
java枚举类型的定义使用介绍,还有示例。
Java ---- enum --- 枚举类案例
java高级编程 Enum枚举 包括枚举的例子,问题 及一些文档,是复习的好资源
ava enum 枚举的spring boot2.x完美实现demo源码。java的枚举类型,可以理解为一种特殊的java类
对java下enum的最详细介绍想详细了解enum内在的同学可以下载学习一下
主要介绍了java中enum的用法,包括了枚举类型的基本定义及用法分析,对于学习Java有着一定的学习与借鉴价值,需要的朋友可以参考下