- 浏览: 3014871 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
Java语言规范第三版8.9规定了enum里的构造器、初始化器和初始化块中不得引用该enum中非编译时常量的静态成员域。
规范特别指出构造器与初始化器禁止访问静态成员域是为了禁止一些循环初始化的状况。例子是:
Java枚举类型中的枚举成员是静态成员,它们会首先被静态初始化;其它成员都只能在枚举成员之后声明,如果通过初始化器(如上例)来初始化的话,则开始初始化RED时静态变量colorMap尚未被赋值。
初始化RED时要调用Color的构造器。如果允许构造器访问colorMap,就会对null调用了put()方法,于是遇到NullPointerException。
规范认为添加了上述限制后就可以让这种循环初始化的代码无法编译,从而杜绝其造成运行时异常的问题。
今天突然想起我前段时间才见到别人问过enum的初始化问题,而且就是遇到了静态初始化失败的错误。问了几个同学都说没问过我,稍微搜了下JavaEye问答频道也没看到。我还会是在哪里看到的呢,怪哉。我肯定是RP了……
想了会儿,总算构造出了记忆中见到的那种错误:
留意第17行,被注释掉的代码如果放进来就通不过编译,跟规范里提到的要避免的状况一样。但是把同样的逻辑放到了成员方法之后,我们就成功的看到了静态初始化错误:
留意调用栈的状况。“... 1 more”没有显示出来的那个是Demo.main。它调用了PowerOfTwo枚举类型上的静态方法,引发了该类型的静态初始化(PowerOfTwo.<clinit>);其中,RED成员首先被初始化,调用构造器(PowerOfTwo.<init>);构造器则调用了成员方法registerValue来添加映射信息,访问到尚未被初始化到HashMap实例的静态成员域map,然后就出错了。
也就是说上述限制的作用很有限……跟泛型有的一拼,呵呵。
知道了问题没关系,只要问题有解决的办法就行。规范中也提供了Color例子的正确写法:
关键点是在声明了静态成员域之后,在一个静态初始化块里来完成其内容的填充,而不要急着在构造器里就去做。当然要是在构造器里先判断一下null然后做合适的初始化也不是不行,但那样代码长了而且每构造一个实例都要检查一次,麻烦。原本需要针对每个实例做的初始化可以靠values()方法遍历所有的枚举成员来做。
回到PowerOfTwo的例子,那就是改成:
Effective Java, 2nd的Item 33有关于嵌套枚举类型的初始化的例子。
这个例子教育我们写Java代码的时候顺序要注意清楚了,不然一个不小心就……||||
好吧我不是不写Java代码或者不写Java帖的。虽然现在用得不多,我还是得保持最低限度的熟练才行 T.T
引用
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
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); } } }
Effective Java, 2nd的Item 33有关于嵌套枚举类型的初始化的例子。
这个例子教育我们写Java代码的时候顺序要注意清楚了,不然一个不小心就……||||
好吧我不是不写Java代码或者不写Java帖的。虽然现在用得不多,我还是得保持最低限度的熟练才行 T.T
发表评论
-
The Prehistory of Java, HotSpot and Train
2014-06-02 08:18 0http://cs.gmu.edu/cne/itcore/vi ... -
MSJVM and Sun 1.0.x/1.1.x
2014-05-20 18:50 0当年的survey paper: http://www.sym ... -
Sun JDK1.4.2_28有TieredCompilation
2014-05-12 08:48 0原来以前Sun的JDK 1.4.2 update 28就已经有 ... -
IBM JVM notes (2014 ver)
2014-05-11 07:16 0Sovereign JIT http://publib.bou ... -
class data sharing by Apple
2014-03-28 05:17 0class data sharing is implement ... -
Java 8与静态工具类
2014-03-19 08:43 16131以前要在Java里实现所谓“静态工具类”(static uti ... -
Java 8的default method与method resolution
2014-03-19 02:23 10324先看看下面这个代码例子, interface IFoo { ... -
HotSpot Server VM与Server Class Machine
2014-02-18 13:21 0HotSpot VM历来有Client VM与Server V ... -
Java 8的lambda表达式在OpenJDK8中的实现
2014-02-04 12:08 0三月份JDK8就要发布首发了,现在JDK8 release c ... -
GC stack map与deopt stack map的异同
2014-01-08 09:56 0两者之间不并存在包含关系。它们有交集,但也各自有特别的地方。 ... -
HotSpot Server Compiler与data-flow analysis
2014-01-07 17:41 0http://en.wikipedia.org/wiki/Da ... -
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22245(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
对C语义的for循环的基本代码生成模式
2013-10-19 23:12 21734之前有同学在做龙书(第二版)题目,做到8.4的练习,跟我对答案 ... -
Java的instanceof是如何实现的
2013-09-22 16:57 0Java语言规范,Java SE 7版 http://docs ... -
oop、klass、handle的关系
2013-07-30 17:34 0oopDesc及其子类的实例 oop : oopDesc* ... -
Nashorn各种笔记
2013-07-15 17:03 0http://bits.netbeans.org/netbea ... -
《深入理解Java虚拟机(第二版)》书评
2013-07-08 19:19 0值得推荐的中文Java虚拟机入门书 感谢作者赠与的样书,以下 ... -
豆列:从表到里学习JVM实现
2013-06-13 14:13 48101刚写了个学习JVM用的豆列跟大家分享。 豆列地址:http: ...
相关推荐
java中enum枚举的详细用法。 0.0
主要介绍了java 中enum的使用方法详解的相关资料,希望通过本文能帮助到大家,理解掌握java 中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 SE程序 Enum枚举类...
Java中的Enum的使用与分析
Java中enum的用法.pdf
Java enum的用法详解,可作为开发api
博文“Java 语言中 Enum 类型的使用介绍”的源码。
java enum详细教程。由浅入深,包括基本语法方面..很适合新手学习。/n各位看官。绝对超值。
enum李兴华视频笔记,绝对值得看!
NULL 博文链接:https://rensanning.iteye.com/blog/2013734
java枚举类型的定义使用介绍,还有示例。
Java ---- enum --- 枚举类案例
java高级编程 Enum枚举 包括枚举的例子,问题 及一些文档,是复习的好资源
ava enum 枚举的spring boot2.x完美实现demo源码。java的枚举类型,可以理解为一种特殊的java类
对java下enum的最详细介绍想详细了解enum内在的同学可以下载学习一下
主要介绍了java中enum的用法,包括了枚举类型的基本定义及用法分析,对于学习Java有着一定的学习与借鉴价值,需要的朋友可以参考下
NULL 博文链接:https://janeky.iteye.com/blog/463611