1、
public class Test2 extends Test1
{
{
System.out.print("1");
}
Test2()
{
System.out.print("2");
}
static
{
System.out.print("3");
}
{
System.out.print("4");
}
public static void main(String[] args)
{
new Test2();
}
}
class Test1
{
Test1()
{
System.out.print("5");
}
static
{
System.out.print("6");
}
}
==========================================================
2、
public class Test3 extends Test4
{
int i=30;
Test3()
{
print();
i=40;
}
public static void main(String[] args)
{
System.out.println(new Test3().i);
}
void print()
{
System.out.println(i);
}
}
class Test4
{
int i=10;
Test4()
{
print();
i=20;
}
void print()
{
System.out.println(i);
}
}
public class Test2 extends Test1
{
{
System.out.print("1");
}
Test2()
{
System.out.print("2");
}
static
{
System.out.print("3");
}
{
System.out.print("4");
}
public static void main(String[] args)
{
new Test2();
}
}
class Test1
{
Test1()
{
System.out.print("5");
}
static
{
System.out.print("6");
}
}
==========================================================
2、
public class Test3 extends Test4
{
int i=30;
Test3()
{
print();
i=40;
}
public static void main(String[] args)
{
System.out.println(new Test3().i);
}
void print()
{
System.out.println(i);
}
}
class Test4
{
int i=10;
Test4()
{
print();
i=20;
}
void print()
{
System.out.println(i);
}
}
child's static field.
parent's constructior
child's constructior
child's static field.parent's field.
parent's constructior
child's field.
child's constructior
还有就是你的print()是覆盖了父类的方法。因此在调用父类的print时。它们调子类的方法。
public class Test3 extends Test4
{
int i=30;
{
System.out.println("op3="+i);
}
Test3()
{
super();
System.out.println("Test3="+i);
print();
i=40;
}
public static void main(String[] args)
{
System.out.println("ss3="+new Test3().i);
}
void print()
{
System.out.println("prt3="+i);
System.out.println(i);
}
}
class Test4
{
int i = 10;
{
System.out.println("op4="+i);
}
Test4()
{
System.out.println("Test4 Con="+i);
print();
}
void print()
{
System.out.println("prt4="+i);
System.out.println(i);
}
}
规则这样:首先要执行的是static函数或者变量,顺序有上到下,有父类到子类,之后是父类的初始块和构造函数,最后是子类的初始块和构造函数
第二题:加载顺序在第一题中已经说到,jvm实例化test4后,调用print,但实际在运行是test4实例化,所以jvm去载入test4的print方法,由于test4的i整形还未被赋值(疑问:jvm会先为test4申明一个i的整型?),所以,打印会是0,接着jvm去执行test4,但是为什么会是30,40而不是40,40,又糊涂了。个人的愚见,仅供各位参考。
0.在进行其它工作之前,分配给这个对象的内存会先被初始化为二进制的零;
1.调用基类的构造函数。这是一个递归过程,因此会先创建继承体系的根,然后是下一级派生类,以次类推,直到最后一个继承类的构造函数。
2.成员对象按照其声明的顺序进行初始化。---第二题就是如此
3.执行继承类的构造函数的正文。
假设你在类中的一个数据字段是一个对象如:MyClass myobject=new MyClass();则此构造对象一定在其所在类的构造函数之前被创建
http://blog.csdn.net/Fitzwilliam/archive/2006/03/28/641593.aspx
====================================================================================
第二个程序涉及到的是多态(Polymorphism)的问题。
由于Test4的print()方法被其子类Test3重写了(Override),所以在运行时调用的方法是重写后的方法。
可以这样理解:
当你new了一个Test3的时候,实际上已经先new了一个Test4,不过此时Test4中所有被重写过的方法都已经被替换了(换成了子类重写后的方法)。
new一个Test3之前,要先new一个它的父类Test4。由于运行时绑定(late-binding),所以创建Test4对象时,Test4的构造器所调用的方法print()是Test3重写后的方法,即Test3中的print()方法;此时,Test3对象还没有创建,所以Test3中的成员变量 i 还没有被初始化,其值为加载时赋的默认值 0.
再看thinking in java