蜡笔小新之超级美味:Java学习之神奇的初始化

来源:百度文库 编辑:中财网 时间:2024/04/28 07:19:22
Java学习之神奇的初始化
作者: yjwgeg
Friday, March 5 2004 9:50 AM
java在初始化的时候也有很多讲究,因为java中出现了类,所以在初始化的时候就有可能使用到创建新对象,所以,对于初始化的顺序要求的比较严格,请看下面一个程序,是thinking in java中的一个程序,被我稍加改编,这样可以更好的说明几个初始化的要点:

class Cup {
Cup(int marker)
{
System.out.println("Cup(" + marker + ")");
}
void f(int marker)
{
System.out.println("f(" + marker + ")");
}
}
class Cups {
static Cup c1=new Cup(1);
Cup c3=new Cup(3);
static Cup c2= new Cup(2);
Cups()
{
System.out.println("Cups()");
}
Cup c4=new Cup(4);
}
public class ExplicitStatic {
Cups c=new Cups();
{
System.out.println("Hello");
}
public static void main(String[] args)  {
System.out.println("Inside main()");
Cups.c1.f(99);
ExplicitStatic x=new ExplicitStatic();
}
static Cups x = new Cups();
}
大家可以手动执行一下这个程序,考虑一下结果是什么,然后参照下面的答案对照一下,看看是否正确:
Cup(1)
Cup(2)
Cup(3)
Cup(4)
Cups()
Inside main()
f(99)
Cup(3)
Cup(4)
Cups()
Hello
我总结了四个初始化的要点,如下:
1、如果有static,即静态成员定义,首先初始化static的变量,如,在类Cups中c3在c2前面,可是在输出的结果中,你可以发现,c2是在c3前执行的,这就是因为,所有的static都在第一时间被初始化。
2、Static只初始化一次,在第二次创建类的对象的时候,就不会去执行static的语句,如,在第二次执行new Cups()的时候,就只输出了Cup(3)和Cup(4),显然,static的两个创建对象的语句没有做。
3、变量的初始化在方法前。如,在Cups类中,方法Cups()在语句Cup c4=new Cup(4)之前,可是输出结果的时候,打印的Cups()却在Cup(4)之后。
4、 在含有main的类中执行顺序是先做static,然后就是main,而不是像其它类一样,除了static就按顺序做下来。如,在main函数中,如果去掉语句ExplicitStatic x=new ExplicitStatic(),则Cups c=new Cups()和System.out.println("hello")都不会执行。另外,留个小问题,如果去掉了System.out.println("hello")外的括号会怎么样呢?
原来java的初始化这么复杂,结合在其他地方查到的资料,总结如下:
(1)java的初始化分为类的初始化(clinit)和实例初始化(init),类的初始化先于实例初始化
(2)java类初始化的原则:
如果当前类继承了其他父类,则先执行父类的类初始化;父类初始化完毕,才开始子类的初始化 类初始化时,clinit将static 变量和static的代码块收集到初始化容器中进行初始化,该动作是在类初始化的时候进行,因此只会进行一次 同级static 成员初始化的顺序按照前后顺序进行
(3)实例初始化的原则:
实例初始化的原则:实例变量和普通代码在构造函数之前初始化 实例变量和普通代码块在调用构造函数之前完成初始化,即构造函数是完成实例初始化的最后一步(除非实例变量的初始化过程中,调用了构造函数) 综合的执行顺序:父类的实例变量--父类的构造函数--当前类的实例变量--当前类的构造函数
注: 代码块是指用{ }包含的代码,比如{System.out.println("ssss")},可以是静态的也可以不是,实际用的不是很多
为了说明上面的原则,再添加两个范例,都是从网络上找的,感谢这么多好心的人共享出的他们的研究成果
下面这个例子演示了由于初始化不当,导致的问题
package test;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class CacheEnumResolver {
// 单态实例 一切问题皆由此行引起
private static CacheEnumResolver SINGLE_ENUM_RESOLVER = new CacheEnumResolver();
/**
* MSGCODE->Category内存索引
*/
private static Map CODE_MAP_CACHE;
static {
CODE_MAP_CACHE = new HashMap();
// 为了说明问题,我在这里初始化一条数据
CODE_MAP_CACHE.put("0", "北京市");
}
// private, for single instance
private CacheEnumResolver() {
// 初始化加载数据 引起问题,该方法也要负点责任
initEnums();
}
/** * 初始化所有的枚举类型 */
public static void initEnums() {
// ~~~~~~~~~问题从这里开始暴露 ~~~~~~~~~~~//
if (null == CODE_MAP_CACHE) {
System.out.println("CODE_MAP_CACHE为空,问题在这里开始暴露.");
CODE_MAP_CACHE = new HashMap();
}
int i=1;
CODE_MAP_CACHE.put("1", "北京市");
CODE_MAP_CACHE.put("2", "云南省");
// ..... other code...
}
public Map getCache() {
return Collections.unmodifiableMap(CODE_MAP_CACHE);
}
/**
* * 获取单态实例 * *
*
* @return
*/
public static CacheEnumResolver getInstance() {
return SINGLE_ENUM_RESOLVER;
}
public static void main(String[] args) {
System.out.println(CacheEnumResolver.getInstance().getCache());
}
}
这是另外一个,展示除了继承情况下,初始化的情况:
package test;
public class Test1 {
{
System.out.print("7 ");
}
private Cup cup = new Cup(2);
Test1() {
System.out.print("5 ");
}
static {
System.out.print("6 ");
}
}
package test;
public class Test2 extends Test1 {
static {
System.out.print("3 ");
}
static Test2 ts2 = new Test2();
private Cup cup = new Cup(1);
{
System.out.print("1 ");
}
Test2() {
super();
System.out.print("2 ");
}
{
System.out.print("4 ");
}
public static void main(String[] args) {
new Test2();
}
}