问题1:类的初始化顺序public class Test1 {
public static int k=0;
public static Test1 t1=new Test1("t1");
public static Test1 t2=new Test1("t2");
public static int i=print("i");
public static int n=99;
public int j=print("j");
{
print("构造块");
}
static{
print("静态块");
}
public Test1(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...strings ){
}
}输出结果:
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问题:i和n到底是什么时候声明的,public static Test1 t1=new Test1("t1");这句会去执行构造块和构造方法,但是这时候public static int i=print("i");并没执行,i是哪里出来的?它是按顺序先声明所有变量然后才从头再挨个赋值吗?问题2:enum的构造方法里为什么不能引用静态变量public enum Test2 {
A,B,C,D,E,F,G;
public static int i=11;
private Test2(){
i=22;
}
}我从the java programming language里找了一段解释,但是看的不太明白,而且感觉解释的很浅,有点转不过来弯,麻烦高人来讲解下原因,最好能举个例子,像我上面的那段代码,我感觉没什么不可以阿
There are three restrictions on the definition of an enum constructor:All enum constructors are private. While you can use the private access modifier in the constructor declaration, by convention it is omitted. Private constructors ensure that an enum type cannot be instantiated directly.The constructor cannot explicitly invoke a superclass constructor. The chaining to the super constructor is handled automatically by the compiler.An enum constructor cannot use a non-constant static field of the enum.This last restriction requires a little explanation. Because each enum constant is a static field of the enum type, the constructors are executed during static initialization of the enum class. The enum constant declarations must be the first declarations in the type, so the constructors for these values will always be the first code executed during static initialization. Any other static fields will be initialized afterward. So if a constructor were to refer to a static (non-constant) field of the enum, it would see the default uninitialized value. This would nearly always be an error, and so it is simply disallowed.
public static int k=0;
public static Test1 t1=new Test1("t1");
public static Test1 t2=new Test1("t2");
public static int i=print("i");
public static int n=99;
public int j=print("j");
{
print("构造块");
}
static{
print("静态块");
}
public Test1(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...strings ){
}
}输出结果:
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问题:i和n到底是什么时候声明的,public static Test1 t1=new Test1("t1");这句会去执行构造块和构造方法,但是这时候public static int i=print("i");并没执行,i是哪里出来的?它是按顺序先声明所有变量然后才从头再挨个赋值吗?问题2:enum的构造方法里为什么不能引用静态变量public enum Test2 {
A,B,C,D,E,F,G;
public static int i=11;
private Test2(){
i=22;
}
}我从the java programming language里找了一段解释,但是看的不太明白,而且感觉解释的很浅,有点转不过来弯,麻烦高人来讲解下原因,最好能举个例子,像我上面的那段代码,我感觉没什么不可以阿
There are three restrictions on the definition of an enum constructor:All enum constructors are private. While you can use the private access modifier in the constructor declaration, by convention it is omitted. Private constructors ensure that an enum type cannot be instantiated directly.The constructor cannot explicitly invoke a superclass constructor. The chaining to the super constructor is handled automatically by the compiler.An enum constructor cannot use a non-constant static field of the enum.This last restriction requires a little explanation. Because each enum constant is a static field of the enum type, the constructors are executed during static initialization of the enum class. The enum constant declarations must be the first declarations in the type, so the constructors for these values will always be the first code executed during static initialization. Any other static fields will be initialized afterward. So if a constructor were to refer to a static (non-constant) field of the enum, it would see the default uninitialized value. This would nearly always be an error, and so it is simply disallowed.
解决方案 »
- 关于一个冒泡算法的例子求解
- 请高手解答 谢谢 谢谢
- 请教:定义一个Student类,要求在程序中生成若干个Student对象,并将这些对象分别保存到ArrayList和HashSet中,然后遍历的输出出来。我这样
- 新手请教句柄问题!多谢撒!
- 文字列连接效率的问题(a+b ? a.concat(concat)? 还是用StringBuffer)
- java里要用一些类,为何有些要new有些不要
- 请教java读取ftp服务器上的文件的问题
- 招聘...(in Shanghai) up者有分
- 项目里面包含音频文件,怎么包音频文件打包进jar?
- 如何转换数据类型
- 几道小小的题目一起和大家更进一步地了解 Java (Ⅳ)
- Swing做的QQ,(续一).............................
问题2看一下enum的具体实现即可,我的分析:http://blog.csdn.net/ZangXT/archive/2008/10/29/3174741.aspx
直接看我的blog中的代码理解即可.
什么时候执行的public static int i=print("i");已经打印的很清楚了
第一个单步or输出lz应该知道顺序吧
看到你的print的了 ,我的意思是说你单步执行就可以发现执行原理了.每次进入的是哪一句话就很清楚了.
public static int k=0;
public static Test1 t1=new Test1("t1");
public static Test1 t2=new Test1("t2");
public static int i=print("i");
public static int n=99; public int j; static{
print("静态块");
} public Test1(String str){
j=print("j");
print("构造块");
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 Test1(String...strings ){ }
}
关于这个问题:类的生命周期分为如下几个阶段,Loading,Linking,Initialization.
Loading之后会对class文件进行Verification,也就是验证.然后是Preparation阶段,注意在这个阶段所有的类变量,也就是class变量,会被默认初始化,也就是int,long,short,浮点等基本类型初始化为0,引用初始化为null,boolean被初始化为false.也就是到这个阶段各个static变量已经有默认的值了,后面会进入Resolution阶段,然后才是初始化,即Initialization,这个阶段会执行static初始化,把变量初始化为你指定的值.也就是在这个阶段k=0;Test1 t1=new Test1("t1");才开始执行的,这时候i=print("i");还没有执行到,i仍然取在 Preparation阶段得到的默认值0.
这样应该清楚了吧.
可以看看这个: http://www.artima.com/insidejvm/ed2/lifetype.html
第一个单步or输出lz应该知道顺序吧
}
我还重来没见过 这样写的代码??
2.当出现第一个new 时进行父:属性--》子属性的初始化(非static,第一步初始已经完了)。。其中注意属性中的new。。若存在则先调用他对应的的构造函数。
3. 2后 父:构造器--》子构造器的初始化
public static int k=0;
public static Test1 t1=new Test1("t1");
public static Test1 t2=new Test1("t2");
public static int i=print("i");
public static int n=99;
// public int j=print("j");
{
print("构造块");
}
static{
print("静态块");
}
public Test1(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...strings ){
}
}
结果是:
1:构造块 i=0 n=0
2:t1 i=1 n=1
3:构造块 i=2 n=2
4:t2 i=3 n=3
5:i i=4 n=4
6:静态块 i=5 n=99
但是有点一好处,如下:
void test(String... strings){
// 这里面取值和数组一样
System.out.print(strings.length);
for(String str : strings) {
System.out.print(str+",");
}
}调用的时候下面这些写法都可以。
test("a");
test("a", "b");
test("a", "b", "c");
test("a", "b", "c", "d");
...
第一步:JVM会装载需要用到的类,类在被装载的时候,会先运行静态代码块(只要被static修饰的方法,变量。都会在被实例化之前装入);JVM装载类的顺序是从基类(Object)开始的;
第二步:实例化类。在实例化类的时候会先执行实例代码块之后再调用构造函数,通常是使用new关键字,调用类的构造函数;除Object类外,其他类都需要调用父类的构造方法super()(隐式的);如果该类的父类还有父类,则需要调用父类的super()构造函数,直到根类Object为止。从方法栈可以看出,实例化是从基类开始的。 public class TestCh3_6 extends Nic{
public static void main(String[] args) {
System.out.println("pre ");
new TestCh3_6();
System.out.println("end ");
}
}
class Bird{
static{System.out.println("classLoder this Bird");}
{System.out.println("b1 ");}
Bird(){
System.out.println("b2 ");
}
}
class Nic extends Bird{
static {System.out.println("r1 ");}
public Nic(){System.out.println("r2 ");}
{System.out.println("r3 ");}
static {System.out.println("r4 ");}
}
分析:TestCh3_6 extends Nic;Nic extends Bird;Bird extend Object;
程序在进入mian()之前要装载4个类,TestCh3_6,Nic,Bird,Object
装载Object,之后装载Bird,运行静态代码块,print:classLoder this Bird
装载Nic,运行静态代码块,print:r1 r4 (按照代码块在上下文的顺序运行)
装载TestCh3_6。装载完毕;
运行mian(),print: pre;
实例化TestCh3_6,隐式递归调用super();直到Object();
实例化完Object之后,实例化Bird,先运行实例代码块 print:b1
之后运行构造函数 Bird();print:b2 实例化结束;
实例化Nic,先运行实例代码块print:r3
之后运行构造函数Nic();print:r2;
最后运行testch3_6的构造函数;实例化完成
运行下一条语句,print: end
退出main()
// 这里面取值和数组一样
System.out.print(strings.length);
for(String str : strings) {
System.out.print(str+",");
}
}调用的时候下面这些写法都可以。
test("a");
test("a", "b");
test("a", "b", "c");
test("a", "b", "c", "d");
...
我还是不太明白输出结果为什么先输出:1:j i=0 n=0,静态变量不是在非静态变量之前初始化吗?
1.类被调用:(针对这个例子就是main方法启动)
A:加载类变量,默认初始化(从上至下)
B:给类变量赋值,以及加载static代码块(从上至下)
仅被加载一次 2.创建对象(针对new运算符)
A:加载成员变量,默认初始化
B:给成员变量初始化,以及加载代码块
C:调用构造器就这个例子而言:先是加载int k , Test1 t1 , Test1 t2 , int i , int n 并给默认值
再是k=0 , t1=new Test1("t1")
当new Test1("t1") 时 先是加载int j 并给默认值
再是j=print('j') 调用print()方法 打印出 1:j i=0 n=0
再调用代码块 打印出 2:构造块 i=1 n=1
再调用构造器 打印出 3:t1 i=2 n=2
t2=new Test1("t2")
当new Test1("t2") 时 先是加载int j 并给默认值
再是j=print('j') 调用print()方法 打印出 4:j i=3 n=3
再调用代码块 打印出 5:构造块 i=4 n=4
再调用构造器 打印出 6:t2 i=5 n=5
i=print("i")
调用print()方法 打印出 7 :i i=6 n=6
此时的i=7了 n=99
再加载静态代码块 打印出: 8:静态块 i=7 n=99