阿里巴巴面试题的java初始化问题

Ikeepmoving 软件开发工程师  2014-02-10 08:42:03

public class Test {  
public static int k=0;
public static Test t1=new Test("t1");
public static Test t2=new Test("t2");
public static int i=print("i");
public static int n=99;
private int a=0;
public int j=print("j");
{
print("构造块");
}
static
{
print("静态块");
}
public Test(String str)
{
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++i;++n;
}
public static int print(String str)
{
System.out.println((++k)+":"+str+" i="+i+" n="+n);
++n;
return++i;
}
public static void main(String args[])
{
Test t=new Test("init");
}
}


输出结果:
1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102

解析:
1.若没有main函数中的代码,结果1-8仍可输出,因为这是在程序编译时就执行的
2.对于类中的各代码的执行顺序:静态变量在类编译时全部初始化,非静态变量仅在实例化时才初始化
所以先初始化t1,newTest1()时会将类中非静态变量初始化,所以初始化j,非静态代码块,然后调用构造函数,t2亦是如此,最后类编译完后,进入main函数,执行t,t初始化前先将Test中非静态变量初始化,然后调用构造函数
按照上面的解析,可以理解,但是有一些疑问。初始化t1,newTest1()的时候会将类中的非静态变量初始化,所以初始化j,非静态代码块,然后调用构造函数,那调用newTest1()的时候,按照先初始化静态,然后初始化非静态的顺序,不久又要初始化t1了么?这样不就又进行了不断的循环了么?这块儿很不理解。不是一定要先把静态都初始化完,才初始化非静态么?
真诚的请大牛指点!!!
...全文
1212 点赞 收藏 27
写回复
27 条回复
super阿利 2014年09月20日
static静态变量初始化,构造函数调用(每次都执行,初始化非静态变量,方法,目的就是防止构造函数调用非静态方法属性) * 构造函数执行,main函数执行 * * 其实记住三点就行了~~~~搞的我都郁闷死了,给大家总结下: * 1.先顺序加载static变量 * 2.无论何时只要执行构造函数,那么在执行构造函数方法体之前必须完成非静态变量,方法的加载(不限次数) * 3.static执行完成后,classloader会执行main方法体,然后就正常执行呗~~~ 可以看看我的博客~~写的比较详细~ http://blog.csdn.net/supera_li/article/details/39431663
回复 点赞
ifvlr 2014年02月21日
这个题是第5次出现在这个论坛上了。最早是在08年出现的 还被加了精华的帖子 http://bbs.csdn.net/topics/390607692
回复 点赞
代码间的舞者 2014年02月21日
引用 24 楼 qyp199312 的回复:
[quote=引用 3 楼 u012814506 的回复:] 就是应该按照先静态成员后普通成员来初始化呀,还有很多静态成员没有初始化完,为什么就可以调用构造函数了?
java的加载顺序应该是这样的: main第一句之前载入类,只载入static修饰的语句。 变量或者是方法块优先顺序按照代码排列上下决定。 静态方法载入不执行。 之后若是遇到调用构造器的,从上到下依次执行非静态变量定义、方法块。 相对而言 , 构造器优先级最低。 [/quote] 学习了!
回复 点赞
袁慎建@ThoughtWorks 2014年02月21日
lz你好,这个题很经典,我已经在博客中做出相关的分享,欢迎访问学习交流噢: Java对象初始化详解:http://blog.csdn.net/ysjian_pingcx/article/details/19605335
回复 点赞
zlmlczcmlvsaav 2014年02月21日
学习了!!谢谢分享!
回复 点赞
平菇虾饺 2014年02月21日
引用 3 楼 u012814506 的回复:
就是应该按照先静态成员后普通成员来初始化呀,还有很多静态成员没有初始化完,为什么就可以调用构造函数了?
java的加载顺序应该是这样的: main第一句之前载入类,只载入static修饰的语句。 变量或者是方法块优先顺序按照代码排列上下决定。 静态方法载入不执行。 之后若是遇到调用构造器的,从上到下依次执行非静态变量定义、方法块。 相对而言 , 构造器优先级最低。
回复 点赞
平菇虾饺 2014年02月21日

package logic;

public class Ali {
	//顺序执行 ------------>静态修饰无论如何只会被装载一次.
	public static int k=0;					//二、k=0;
	public static Ali t1 = new Ali("t1");  	//三、new Ali("t1")
	public static Ali t2 = new Ali("t2");  	//七、new Ali("t2");
	public static int i = print("i");  	   	//十一、静态变量与静态构造块优先执行,但是得按照先后次序(在代码中的)
	public static int n = 99;  			   	//十二、n=99;
	static   								//十三、静态构造块无论如何也只能被执行一次.与静态变量之间按照先后次序决定。
	{  
		print("静态块");  
	}  
	public static int print(String str)  //九下、(合并九上)	//十二、静态方法不执行
	{  
		/*静态方法如果不被调用不会主动执行.*/
		System.out.println((++k)+":"+str+"   i="+i+"    n="+n);  
		++n;  
		return ++i;  
	} 
	//------------------------------------\\
	//-------------以上为static-------------\\
	//------------------------------------\\
	public int j = print("j");				//四、非静态元素定义与非静态方法块按上下顺序执行	//八、非静态变量执行是new多少次就执行多少次的		//十五、再次执行,这是来自main里面的呼唤
	
	{  //五、非静态构造块优先构造器执行,但与非静态变量按上下先后顺序		//九、非静态构造块优先构造器执行,但与非静态变量按上下先后顺序		//十六、这是来自main里面的呼唤
		print("构造块");  
	} 
	public Ali(String str)  //六、构造器		//十、构造器		//十七、这儿执行完毕之后就不会再执行了.
	{  
		System.out.println( (++k) + ":"+str+"   i="+i+"    n="+n);  
		++i;
		++n;  
	}
	//------------------------------------\\
	//-------------以上非static-------------\\
	//------------------------------------\\
	public static void main(String[] args) {//一、大约步骤--装载static修饰的	
		new Ali("init ... ");				//十四、执行 new Ali("init ... ");
	}
}
那样是不会造成死循环的,要读懂java的加载顺序。 上学期学长们实习回来就说了这个问题。我这儿做了点批注,有错请轻拍
回复 点赞
代码间的舞者 2014年02月20日
引用 8 楼 u012974494 的回复:
简单来说静态变量和静态代码块优先执行,而在静态变量和静态代码块中的方法不会再去执行类中的静态变量和静态代码块,静态的东西都只加载一遍,所以是先加载public static Test t1=new Test("t1"); 而在实例化过程中不会再去加载静态的变量和代码块,以此类推
嗯,实例化只是调用构造函数,不会涉及到静态静态变量和静态代码
回复 点赞
rockets311 2014年02月20日
回复 点赞
zhujunhua2012 2014年02月20日
引用 8 楼 u012974494 的回复:
简单来说静态变量和静态代码块优先执行,而在静态变量和静态代码块中的方法不会再去执行类中的静态变量和静态代码块,静态的东西都只加载一遍,所以是先加载public static Test t1=new Test("t1"); 而在实例化过程中不会再去加载静态的变量和代码块,以此类推
+1
回复 点赞
代码间的舞者 2014年02月18日
学习了
回复 点赞
etam520 2014年02月18日
以上是执行步骤,了解了整段代码的执行顺序,就懂了。希望对你有所帮助
回复 点赞
etam520 2014年02月18日
public class Test { public static int k=0; ①main开始,先执行左边初始化Test t k=0 public static Test t1=new Test("t1"); //②实例化new Test,跳到a=0,执行print("j"),输出1:j i=0 n=0 ③执行print("构造块"),输出2:构造块 i=1 n=1 ④执行public Test(t1) ,输出3:t1 i=2 n=2这句执行完毕。// public static Test t2=new Test("t2");//⑤同理可得输出4:j i=3 n=3 5:构造块 i=4 n=4 6:t2 i=5 n=5 public static int i=print("i"); //⑥继续初始化Test t 执行这句输出7:i i=6 n=6 public static int n=99; //⑦执行这句,n=99 private int a=0; private int j = print("j"); { print("构造块"); } static{ print("静态块"); //⑧执行这句,输出8:静态块 i=7 n=99 Test t初始化完毕 } public Test(String str){ System.out.println((++k)+":"+str+" i="+i+" n="+n); ++i;++n; } public static int print(String str){ System.out.println((++k)+":"+str+" i="+i+" n="+n); ++n; return++i; } public static void main(String args[]) { // Test t=new Test("init"); //⑨实例化new Test("init"),调到执行a=0;print("j")输出9:j i=8 n=100 ⑩执行{构造块}输出 10:构造块 i=9 n=101 接着执行构造函数Test("init")输出11:init i=10 n=102 执行完毕。 } }
回复 点赞
letingoo 2014年02月14日
啊,好复杂啊
回复 点赞
逍遥jc 2014年02月12日
这不是很久之前的面试题么?
回复 点赞
kardelpeng 2014年02月12日
这个问题应该分为编译Test类,跟实例化Test: 1.编译Test类: 测试方法把 // public static Test t1=new Test("t1"); // public static Test t2=new Test("t2"); // Test t=new Test("init"); 都注释了,运行结果会是: 1:i i=0 n=0 2:静态块 i=1 n=99 没有输出j相关的,那是因为j是成员变量,非静态成员变量。也就是说在不实例化Test的条件下,加载顺序是静态变量,静态块。 2.当有实例化的Test静态变量存在的时候。
public class Test {
	public static int k=0;  
	public static Test t1=new Test("t1");  
//	public static Test t2=new Test("t2");
	public static int i=print("i"); 
	public static int n=99;  
	private int a=0;  
	private int j = print("j");
	{  
	print("构造块");  
	}  
	static{  
	print("静态块");  
	}  
	 public Test(String str){  
		 System.out.println((++k)+":"+str+"   i="+i+"    n="+n);  
	    ++i;++n;  
	 }  
	 public static int print(String str){  
		 System.out.println((++k)+":"+str+"   i="+i+"    n="+n);  
		 ++n;  
	     return++i;  
	 }  
	 public static void main(String args[])  
	 {  
//		 Test t=new Test("init");  
	 } 
}
运行结果: 1:j i=0 n=0 2:构造块 i=1 n=1 3:t1 i=2 n=2 4:i i=3 n=3 5:静态块 i=4 n=99 这说明,在实例化Test类的时候,先初始化的并不是静态变量,而是成员变量,最后加载的静态变量,跟静态快。 但我们在把public static int i=print("i"); 移到public static Test t1=new Test("t1"); 之前运行结果: 1:i i=0 n=0 2:j i=1 n=1 3:构造块 i=2 n=2 4:t1 i=3 n=3 5:静态块 i=4 n=99 说明静态变量的初始化顺序跟位置有关系。
回复 点赞
morning_china 2014年02月11日
引用 3 楼 u012814506 的回复:
就是应该按照先静态成员后普通成员来初始化呀,还有很多静态成员没有初始化完,为什么就可以调用构造函数了?
程序的确是在初始化静态变量public static Test t1=new Test("t1"); , 只不过这个静态变量t1引用了一个Test实例,那只能是构造好这个实例(构造实例时就会初始化实例变量,构造块,构造函数),然后赋值给静态变量t1后,才算初始化完t1; 静态变量t2也是一样的。 另外,说一下: 对于类中的各代码的执行顺序:静态变量在类编译时全部初始化,非静态变量仅在实例化时才初始化 严格的说,静态变量是在类被加载到java虚拟机时,被初始化的,和编译没有关系。
回复 点赞
Ikeepmoving 2014年02月11日
引用 4 楼 hjw506848887 的回复:
[quote=引用 3 楼 u012814506 的回复:] 就是应该按照先静态成员后普通成员来初始化呀,还有很多静态成员没有初始化完,为什么就可以调用构造函数了?
我的想法是这样的,类Test中的两个静态成员变量:public static Test t1=new Test("t1"); public static Test t2=new Test("t2"); 应该先初始化。具体顺序应该是这样的:静态变量—静态块—成员变量—构造方法—静态方法[/quote] 其实不一定先初始化静态变量再初始化静态块的,它们的与顺序有关。
回复 点赞
Mich_LY 2014年02月11日
简单来说静态变量和静态代码块优先执行,而在静态变量和静态代码块中的方法不会再去执行类中的静态变量和静态代码块,静态的东西都只加载一遍,所以是先加载public static Test t1=new Test("t1"); 而在实例化过程中不会再去加载静态的变量和代码块,以此类推
回复 点赞
浪子膏_ 2014年02月11日
又学习到了。。。
回复 点赞
发动态
发帖子
Java SE
创建于2007-09-28

3.4w+

社区成员

30.7w+

社区内容

Java 2 Standard Edition
社区公告
暂无公告