class Depend {
int i = 10; public Depend() {
print();
i = 20;
} void print() {
System.out.println("Depend=> " + i);
}
} public class qdb extends Depend {
int i = 30; public qdb() {
print();
super.print();
i = 40;
} void print() {
System.out.println("Target=> " + i);
}
public static void main(String[] args)
{
new qdb();
}
}
int i = 10; public Depend() {
print();
i = 20;
} void print() {
System.out.println("Depend=> " + i);
}
} public class qdb extends Depend {
int i = 30; public qdb() {
print();
super.print();
i = 40;
} void print() {
System.out.println("Target=> " + i);
}
public static void main(String[] args)
{
new qdb();
}
}
{
int i = 10;
public Depend()
{
print();
i = 20;
} void print()
{
System.out.println("Depend=> " + i);
}
}
public class Qdb extends Depend
{
int i = 30;
public Qdb()
{
print();
super.print();
i = 40;
} void print()
{
System.out.println("Target=> " + i);
} public static void main(String[] args)
{
new Qdb();
}
}给大家整理一下,方便看
自己答错了
Depend=>10
Depend=>20
Target=> 30
Depend=> 30
i赋值为20,然后执行Qdb的构造方法,调用print(),打印出30,在执行父类对象的方法print();因为父类对象
的i已经变为20,所以就打印出20。
Target=> 0 // 这个0怎么回事啊
Target=> 30
Depend=> 20
我认为应该是
Depend=>10
Target=>30
Depend=>20可是编译了怎么会是
Target=> 0
Target=> 30
Depend=> 20
public Depend()
{
print();
i = 20;
}
但是这个print()是调用Qdb类的,因为Qdb重写了这个方法,而此时Qdb中的i声明了但还没有赋值,int型缺省为0,所以就打了Target=> 0出来,然后给超类的i重新赋值20接着Qdb给i赋值30,然后再执行Qdb的构造方法
public Qdb()
{
print();
super.print();
i = 40;
}
这个时候print()打印出Target=> 30就很正常了,super.print()就直接定位到超类里去了,因为超类的i已经被重新赋值20了,所以打印Depend=> 20如果想不明白的话可以把个类中的i字段重构一下,比如把其中一个改为j,其实这两个i完全没有任何联系。
Target=0
难道向上转型了?
{
public void eat()
{
System.out.println(getClass().getName()+"eat");
}
}
class Dog extends Animal
{
public void eat()
{
System.out.println(getClass().getName()+"eat");
}
}
class Pig extends Animal
{
public void eat()
{
System.out.println(getClass().getName()+"eat");
}
}
public class qdb
{
public static void main(String[] args)
{
Animal a1=new Dog();
a1.eat();
Animal a2=new Pig();
a2.eat();
}
}
这个例子比较容易理解
确实 基类初始化,不管到根基类有多少层,每层的方法都会被最终导出类的方法override
首先程序从main方法开始执行,new Qdb(),这句话就是要new一个Qdb的对象,根据对象初始化的顺序,初始化子类之前必须要初始化父类,所以此时一系列的调用开始了
1,调用Qdb的父类Depend类的构造函数,在调用构造函数之前,成员变量是先于构造函数初始化的,这个时候Depend里面的i已经有值了,它的值就是10,在Depend构造函数里面,我们看到的第一句是:print方法,这个print方法我们要注意,它在Depend的子类也定义了,并且此次初始化是由子类Qdb发起的,所以实际上这个print方法调用的是Qdb里面定义的print,而这个时候有意思的事情就出现了,此时子类还没有出生呢,因为这个时候父类才正在构造之中,所以子类中此时的i还是0,而print正好打印出的是子类的i,所以第一次输出是0;
2,父类调用完子类的print后,把父类的i赋了值20,此时父类已经完全被构造出来了,马上就要开始构造子类了.
3,同理,在调用子类的构造函数之前,子类的i被赋了初值30,然后进入子类的构造函数,此时调用的也是print,这个就非常好理解了,这个print肯定是子类自己的print方法了,此时i已经构造好,当然,此时输出的值是30;
4,下一句super.print(),这句话显示的调用了父类的print方法,而此时父类的i已经在父类的构造函数里面改为20了,所以此次调用输出20.
5,然后再把子类的i的值设为50.在以上过程中,如果掌握好了类的初始化顺序,是比较容易知道输出结果的.还有一点要记住,JAVA里面的方法是动态绑定的,而成员却是静态绑定的.父类里面调用的print之所以会输出0,就是因为print实际上调用的是子类的print,因为整个这场调用都是由new Qdb()这句话产生的.
需要认真的体会一下java中的继承和重载才可以努力学习 这个0真是不容易想到。顶
(覆盖一个方法意味着替换它的实现,这样在子类对象上调用该方法时,被调用的就是该方法的子类版本)
所以Target=> 0
其它如下:
Target=> 30
Depend=> 20
Target=> 30
Depend=> 20类的初始化顺序以已经渐渐的清楚很多了
Target=> 30
Depend=> 30
public Depend()
{
print();
i = 20;
}
但是这个print()是调用Qdb类的,因为Qdb重写了这个方法,而此时Qdb中的i声明了但还没有赋值,int型缺省为0,所以就打了Target=> 0出来,然后给超类的i重新赋值20 接着Qdb给i赋值30,然后再执行Qdb的构造方法
public Qdb()
{
print();
super.print();
i = 40;
}
这个时候print()打印出Target=> 30就很正常了,super.print()就直接定位到超类里去了,因为超类的i已经被重新赋值20了,所以打印Depend=> 20
比如说print的第一次调用,当调用子类的构造函数时,先构造父类的,这样就先加载父类的成员变量
但是调用父类构造函数中的print方法,这是this引用实际上是子类,同时子类由于这个方法,
就直接调用子类的方法
Depend=>10;---Target=>0;
Target=>30;√
Depend=>20;√受教了哈。
这里有点疑问,如果说子类还没出生,那它又怎么知道子类的i是int型而自动初始为0呢?
{
int i = 10;
//1.调用父类构造函数
public Depend()
{
//2.调用了子类的print()方法,父类i = 10
print();
//4.此处父类i 赋值为 20
i = 20;
}
//8.由第4步知父类i = 20
void print()
{
System.out.println("Depend=> " + i);
}
}
public class Qdb extends Depend
{
int i = 30;
public Qdb()
{
//5.调用子类print()方法,子类 i = 30;
print();
//7.显示调用父类print()方法
super.print();
//9.此处子类i 赋值为 40
i = 40;
}
void print()
{
//3. 子类i已经被声明为int(默认值为0),未赋值
//6. 子类i已经被赋值为 30
System.out.println("Target=> " + i);
}
public static void main(String[] args)
{
new Qdb();
}
}
这里对第3步不理解,如果说i已经被int i = 30;声明为int,为什么还没赋值呢? 如果没被声明,又为什么会输出 0 呢? 难道说,子类成员变量的声明在父类构造函数之前,而赋值在父类构造函数之后?
二:执行的时候是先调用父类的无参数构造方法,然后再执行子类的方法.
所以结果是:
Target>=0,//这是因为子类重写了父类的方法,所以结果是由执行子类里的方法得来的.
Depend>=30,//执行完了父类的无参数构造方法,然后执行子类的构造方法.
Depend>=20;//super的用法是指调用父类里的构造方法.
不过这样一搞,父类当中是否永远调用不到那些被子类扩展的方法了???看来对于父类中init之类可能被扩展的方法最好还是留空比较好。