我有一个Set类(这是J2ME,所以我对标准API的访问权限有限;只是为了解释我明显的轮子改造)。我正在使用我的set类在类和子类中创建常量集。它有点像......
class ParentClass
{
protected final static Set THE_SET = new Set() {{
add("one");
add("two");
add("three");
}};
}
class SubClass extends ParentClass
{
protected final static Set THE_SET = new Set() {{
add("four");
add("five");
add("six");
union(ParentClass.THE_SET); /* [1] */
}};
}
所有看起来都很好,除了[1]处的行导致空指针异常。据推测,这意味着子类中的静态初始化程序在父类的运行之前运行。这让我感到惊讶,因为我认为它会先在任何新的导入中运行静态块,然后再在instatiated子类中运行。
我在这个假设中是对的吗?有没有办法控制或解决这种行为?
更新
事情甚至更奇怪。我尝试了这个(注意'new ParentClass()'行):
class ParentClass
{
public ParentClass()
{
System.out.println(THE_SET);
}
protected final static Set THE_SET = new Set() {{
add("one");
add("two");
add("three");
}};
}
class SubClass extends ParentClass
{
protected final static Set THE_SET = new Set() {{
System.out.println("a");
new ParentClass();
System.out.println("b");
add("four");
System.out.println("c");
add("five");
System.out.println("d");
add("six");
System.out.println("e");
union(ParentClass.THE_SET); /* [1] */
System.out.println("f");
}};
}
输出很奇怪:
a
["one", "two", "three"]
b
c
d
e
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
所以ParentClass已初始化,但子类在其静态初始化程序中无法访问它。
答案 0 :(得分:7)
这是你想要完成的吗?或者您是否需要本地实现Set接口?
class ParentClass
{
protected final static Set THE_SET;
static {
THE_SET = new HashSet();
THE_SET.add("one");
THE_SET.add("two");
THE_SET.add("three");
}
}
class SubClass extends ParentClass
{
protected final static Set THE_SECOND_SET;
static {
THE_SECOND_SET = new HashSet();
THE_SECOND_SET.add("four");
THE_SECOND_SET.add("five");
THE_SECOND_SET.add("six");
union(ParentClass.THE_SET); /* [1] */
}
}
答案 1 :(得分:3)
不保证类之间的静态初始化顺序。在一个类中,它们按源代码的顺序运行。
如果您考虑一下,那么类之间的命令实际上不可能是因为您无法控制何时加载类;您可以动态加载类,或者JVM可以优化加载顺序。
答案 2 :(得分:2)
即使您没有extends ParentClass
,使用ParentClass
也会导致它被初始化。
当事情变得棘手时,就是你有周期。使用循环,可以在完全初始化之前访问类。由于Java是一个多线程系统,因此您也可能遇到死锁和竞争问题。
可能是你的Java ME实现是错误的(并非闻所未闻)。完整ParentClass
部分引用您的ChildClass
。或许还有一些其他的应用程序/库错误。
在相关的说明中,如果您没有-target 1.4
或更高版本,则内部类的外部不会在您预期的时候立即初始化。如图所示,您的代码在静态上下文中使用(技术上)内部类,因此这不应该是一个问题。
同样有趣的是指出静态初始化在这种情况下略有混淆,因为你实际上有四个类。
答案 3 :(得分:2)
简单地停止滥用匿名类的概念进行实例初始化(所谓的“双支撑习语”)。
答案 4 :(得分:0)
给定[“one”,“two”,“three”]的输出行,ParentClass.THE_SET基本上不可能从未初始化。
当然,可能不仅涉及一个类加载器,但查看空指针发生的方法和行号肯定会有所帮助。
答案 5 :(得分:-1)
我认为类似的东西是用Java拼图书或google关于java技巧的YouTube视频写的。