class Depend
{
int i = 10;
public Depend()
{
print();
i = 20;
}
void print()
{
System.out.println("Depend=> " + this.i);
}
}public class Target extends Depend
{
int i = 30;
public Target()
{
print();
super.print();
i = 40;
}
void print()
{
System.out.println("Target=> " + i);
}
public static void main(String[] args)
{
Target target = new Target();
}
}其执行结果为什么是:Target=>0
Target=>30
Target=>20
{
int i = 10;
public Depend()
{
print();
i = 20;
}
void print()
{
System.out.println("Depend=> " + this.i);
}
}public class Target extends Depend
{
int i = 30;
public Target()
{
print();
super.print();
i = 40;
}
void print()
{
System.out.println("Target=> " + i);
}
public static void main(String[] args)
{
Target target = new Target();
}
}其执行结果为什么是:Target=>0
Target=>30
Target=>20
{
print();
i = 20;
} 父类中的print()方法是调用的子类的print()方法,而此时子类的成员变量还未赋值,所以为0.
构造方法会优先于属性初始化,因为构造代表着分配内存之类的基础功能,只有构造好了,其他的才能使用
那么问题在于Target里面的
public Target()
{
print();
super.print();
i = 40;
}
在第一个print()之前,会优先调用父类的构造器,而父类的构造器里面的print()方法,被override了,实际调用的是子类的方法,可惜,此时子类还没有完成初始化,因为父类的构造器还没有返回呢。 所以其属性全部为默认值。 数字当然就是0啦!
属性初始化应该优先于构造方法,请看下列代码,刚刚自己写的^_^class Father{
int i = f();
int f(){
System.out.println("in Father's f()");
return 1;
}
Father(){
System.out.println("in Father's Father()");
}
}public class Son extends Father{
int i = g();
int g(){
System.out.println("in Son's g()");
return 1;
}
Son(){
System.out.println("in Son's Son()");
}
public static void main(String[] args){
Son s = new Son();
}
}运行结果是:
in Father's f()
in Father's Father()
in Son's g()
in Son's Son()
如:
static int i = 10;
所有变量都改成以上的形式就可以了!
class Father{
static int j = f1();
int i = f();
static{
System.out.println("父类静态方法体");
}
{
System.out.println("父类非静态方法体");
}
static int f1(){
System.out.println("父类静态属性");
return 1;
}
int f(){
System.out.println("父类非静态属性");
return 1;
}
Father(){
System.out.println("父类构造函数");
}
}public class Son extends Father{
static int j = g1();
int i = g();
static{
System.out.println("子类静态方法体");
}
{
System.out.println("子类非静态方法体");
}
static int g1(){
System.out.println("子类静态属性");
return 1;
}
int g(){
System.out.println("子类非静态属性");
return 1;
}
Son(){
System.out.println("子类构造函数");
}
public static void main(String[] args){
Son s = new Son();
}
}lz,按我的初始化顺序跑跑看,你就不会疑惑了,呵呵
public class Depend {
int i = 10;//第4步 public Depend() {//第3步
print();//第5步
i = 20;//第7步
} void print() {
System.out.println("Depend=> " + this.i);//第12步
}
}public class Target extends Depend {
int i = 30;//第8步 public Target() {//第2步
print();//第9步
super.print();//第11步
i = 40;//第13步
} void print() {
System.out.println("Target=> " + i);//第6步,这时子类中的i还为0 第10步 i=30
} public static void main(String[] args) {
Target target = new Target(); //第1步
}
}用断点跟踪一下,就可以看清了。
6楼说的对,构造方法优先于属性初始化是错误的。
而且子类中的i和父类中的i是两个变量。
你看看我在10楼的代码吧^_^
个人觉得这只是debugger定位所要构造类的一个标识定位中转而已
不存在顺序上的混淆
int i = 10;//第4步 public Depend() {//第3步
print();//第5步
i = 20;//第7步
} void print() {
System.out.println("Depend=> " + this.i);//第12步
}
}public class Target extends Depend {
int i = 30;//第8步 public Target() {//第2步
print();//第9步
super.print();//第11步
i = 40;//第13步
} void print() {
System.out.println("Target=> " + i);//第6步,这时子类中的i还为0 第10步 i=30
} public static void main(String[] args) {
Target target = new Target(); //第1步
}
}点解第5步会跳到第六步去????
你没写错吧,应该是下面的结果呀,
Target=> 0
因为print被Traget重载,所以在Depend初始化时调用Traget的print方法,但此时Traget还没有被初始化所以默认为0
Target=> 30
因为先初始化属性值Target构造函数被调用前i=30了,所以输出30
Depend=> 20
Depend后来被设为20所以输出是正确的
结论是对的,但是理由说得不充分。根据class的文件定义(下面这个链接)
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#80959
class里面根本就根本不可能有【int i = 10;】这样的语句。
在看看javac的源代码就知道,比方说下面的代码。public class Test {
int i=1;
int j;
public Test(){
j = 1;
i = 2;
}
}在class里面被搞成下面这个样(用jad反编译就知道):public class Test
{ public Test()
{
i = 1;
j = 1;
i = 2;
} int i;
int j;
}所以属性初始化都被放到缺省构造函数中了,这样的话,执行顺序都应该可以搞明白了。
因为基类的print()方法已经被覆盖,所以基类构造器中的print()方法执行的是子类中的print()方法!
Target=> 30
Depend=> 20
-----------
LZ你DEBUG一下就很清楚了.class Depend {
int i = 10;//1 public Depend() {//2
print();//这里调用的是Target的print(),此时Target的i未初始化,所以是0.
i = 20;
} void print() {
System.out.println("Depend=> " + this.i);
}
}public class Target extends Depend {
int i = 30;//3 public Target() {//4
print();//这里调用的是Target的print(),此时Target的i已初始化,所以是30
super.print();//很明显调用Depend的i,是20
i = 40;
} void print() {
System.out.println("Target=> " + i);
} public static void main(String[] args) {
Target target = new Target();
}
}
而此时子类中的成员变量还没有被初始化,默认值为0,所以第一个输出的结果为0。
好经典的一道题目
//{
//int i = 10;
//public Depend()
//{
//print();
//i = 20;
//}
//void print()
//{
//System.out.println("Depend=> " + this.i);
//}
//}//public class Target extends Depend
public class Target {
// int n = 30;
static int n = 30; //第一步 int i = 19; //第四步 public Target() //第三步
{
System.out.println("n=" + n); // 第5步
System.out.println("i=" + i);// 第6步
print(); //第7步
i = 40; //第10步
} public static void print() {
System.out.println("hello"); //第8步 第13步
System.out.println("Target=> " + n); //第9步 第14步
} public static void main(String[] args) {
Target target = new Target(); //第二步
System.out.println("hello"); //第11步
target.print(); //第12步
}
}
用eclipse调试功能获得步骤
那个public static void print() 静态方法不是在构造函数之前调用,这是什么原因呢?
是正解
同时一任天然★IT民兵的很有道理,自己打个断点debug一遍,一切就清楚了
在执行父类中构造函数中语句i=20,而后执行print()时,因此方法被子类OVERRIDE,
所以动态绑定的原因,实际上执行的是子类的方法,而此时子类并没有初始化完成,所以默认赋值i=0。输出Target=> 0;而后执行子类中构造函数中赋值语句i=30,再执行print()方法。输出Target=> 30;而后执行super.print()语句,指明执行父类中print()方法。输出Depend=> 20。总结完毕。撤!
我做了一下测试,把Target类的print()函数改名,也就是不override,输出结果为
Depend=>10
Target=>30
Depend=>20
这就验证了5楼的说法,也就是:在父类的构造函数里,如果调用到的函数子类有重写,调用的则是子类重写的函数.
所以我觉得5楼的说法是正确的.
以下是一个简单的例子
public class Test {
private int a = 2;
private int b;
private int c = 1;
public Test(){
a = 3;
}
public void print(){
System.out.println("a=" + a);
System.out.println("b=" + b);
System.out.println("c=" + c);
}
public static void main(String[]args){
Test t = new Test();
t.print();
}
}
执行结果:
a=3
b=0
c=1
----------------------
b=0,c=1说明了设初始值生效
而a的初始值本为2的,但最终由于构造函数的初始化工作,把a最终初始为3了.
所以,属性先于构造函数初始化,但属性最后的初始化由构造函数决定.
你说的对,是赋值,我说得不清楚.
我解释一下
在<<core java>>第七版中文版的第一卷的第104页中有这么一句"构造器被运行,并用于将实例域初始化为所希望的状态".
可以理解为,构造函数是为初始化工作而存在的吧?
结合你的意思,在构造函数里,是通过赋值来完成最后的初始化工作,这样说对吗?
在类初始化工作的总过程中,我把构造函数的工作理解作最后的初始化工作,不知这个对不对了,我自己想当然而已,希望有人给个确切的答案.