一个java学习中的测试程序,我搞不懂了,关于集继承的
package test1;/**
*
* @author leslie
*/class MyA {
int a = 1;
public MyA() {
print();
} public void print() {
System.out.println("aaa" + a);
}
}class MyB extends MyA {
int a = 2;
public MyB() {
print();
} public void print() {
System.out.println("bbb" + a);
}
}class MyC extends MyB {
int a = 3;
public MyC() {
print();
} public void print() {
System.out.println("ccc" + a);
}
}public class Main { /**
* @param args the command line arguments
*/
public static void main(String[] args) {
new MyC();
}
}
这个程序在netbean下返回的是:
ccc0
ccc0
ccc3
不知道为什么?那位能给我解释下为什么会这样啊?我只调用了一次为什么3个结果?
而且a没有赋值为0啊?谢谢谢谢
package test1;/**
*
* @author leslie
*/class MyA {
int a = 1;
public MyA() {
print();
} public void print() {
System.out.println("aaa" + a);
}
}class MyB extends MyA {
int a = 2;
public MyB() {
print();
} public void print() {
System.out.println("bbb" + a);
}
}class MyC extends MyB {
int a = 3;
public MyC() {
print();
} public void print() {
System.out.println("ccc" + a);
}
}public class Main { /**
* @param args the command line arguments
*/
public static void main(String[] args) {
new MyC();
}
}
这个程序在netbean下返回的是:
ccc0
ccc0
ccc3
不知道为什么?那位能给我解释下为什么会这样啊?我只调用了一次为什么3个结果?
而且a没有赋值为0啊?谢谢谢谢
int a = 1;
public MyA() {
print();
} public void print() {
System.out.println("aaa" + a);
}
}
///
class MyB extends MyA {
int a = 2;
public MyB() {
print();
} public void print() {
System.out.println("bbb" + a);
}
} class MyC extends MyB {
int a = 3;
public MyC() {
print();
} public void print() {
System.out.println("ccc" + a);
}
}
public class text { /**
* @param args the command line arguments
*/
public static void main(String[] args) {
new MyC();
//当你new一个子类的时候,它会自动调用父类的构造函数,依次向上调用,先调用 MyA (),然后MyB(),最后是MyC(),所以会出现三个结果.
//没有出现三,是因为你的MyC()的构造函数没有打印的.
}
}
/*改成这样的……
**
*/class MyC extends MyB {
int a = 3;
public MyC() {
System.out.println("ccc" + a);
} }
[你的代码我给你缩进了]
提个建议:(比算法还重要)1.大括号对齐.
2.遇到左大括号缩进(简单的Table键缩进).
3.方法和方法之间,方法和属性之间,一些重要的语句之间用空格隔开.
4.并列语句之间加空格. Name MyName = new Name();
5.运算符两侧加空格. int i = 8;
6.成对编程. 写完{后马上写上}.
目的:要让别让看得清楚,要让别人看的舒服.
在调用MyC构造方法之前,先调用父类的无参构造方法(如果父类没有无参构造方法就报错)
此时虽然new还没返回,但this已经有了,由于动态绑定,每次调用父类的构造方法时执行的print()
都是MyC中的print().
在执行父类构造方法时还没执行了a = 3;所以a一直是0(变量没有动态绑定)
一直到把父类构造方法都执行完了
执行a = 3;
在调print()就打印出3了
楼上的是否想这样??class MyC extends MyB {
int a = 3;
public MyC() {
System.out.println("ccc" + a);
} }
呵呵……
对构造函数的调用,先调用超类的,然后依次向下,仅仅调用构造函数,对你的print()视而不见.
对此完全赞成二楼的.你可以稍微改动几处看看效果.
1.把MyA的构造函数改一下,就看清了.
public MyA{
System.out.println("aaa"+a);
}2.你可以对MyC的print()方法改一下,看一下输出,就明白了.
class MyC extends MyB {
int a = 3;
public MyC() {
print();
} public void print() {
System.out.println("ccc+abcccccc" + a); ///////看看输出
}
}
1. ClassLoader加载MyC这个类.
2. 准备调用MyC的构造方法.
3. 准备调用MyC的父类MyB的构造方法.
4. 准备调用MyB的父类MyA的构造方法.
5. 准备调用MyA的父类java.lang.Object的构造方法.
6. 执行java.lang.Object的构造方法.
7. 初始化MyA类的成员变量,a=1;
注意:此时堆栈中对象的分布是MyC的对象持有MyB对象的一个引用,MyB对象持有MyA对象的一个引用,MyA对象持有java.lang.Object对象的一个引用,MyA,MyB,MyC对象中各有一个成员变量a,一定注意,这个时候,堆栈中有三个a,此时MyA的成员变量a=1;MyB和MyC的成员变量a=0;
8. 执行MyA的构造方法,调用print方法
注意:这里有多态,我们调用的方法实际上是MyC对象重写的方法,也就是说内存代码区向外提供调用的print方法是MyC的print方法,由于MyC中的成员变量a=0,所以此时打印"ooo0";
9. 初始化MyB的成员变量.和第7条同理,此时堆栈中MyA的a=1,MyB的a=2,MyC的a=0;
10. 执行MyB的构造方法.和8同理,调用的还是MyC的print方法,所以打印的是"ooo0";
11. 初始化MyC的成员变量.和第7条同理,此时堆栈中MyA的a=1,MyB的a=2,MyC的a=3;
12. 执行MyC的构造方法.和8同理,调用的是MyC的print方法,此时MyC的成员变量a=3,所以打印的是"ooo3";做这个内存分析的时候,主要考虑new MyC();这一句执行的过程:
1. ClassLoader加载MyC;
2. 进入MyC的构造器,首先构造MyC的父类,直到Object,Object之后怎么处理就不清楚了.
3. 处理完父类构造器之后,处理成员变量的初始化.
4. 然后执行构造器中的代码.相关的东西:
多态:一个类继承关系中的重写的方法,在调用的时候,只有一个,那就是重写了那个方法的备份最小的类中的方法体.
//java继承中,要稿清楚三个问题:
//1.子类覆盖与父类同名的方法,即父类同名方法在子类中不可见
//2.子类隐藏父类同名的属性,即父类属性是可见的,但是它的值会变成默认值,并且得有父类的对象或方法调用
//3.构造子类对象时,默认调用父类的无参构造//打印3条是因为子类默认调用父类无参构造打印
//打印0是因为和子类属性同名,变成了默认值0
//详解见下
class MyA {
int a = 1;
public MyA() {
print();
}
public void print() {
System.out.println("aaa" + a);
}
}class MyB extends MyA {
int a = 2;
public MyB() {
print();
}
public void print() {
System.out.println("bbb" + a);
}
}
//MyC类分别继承了MyB,MyA的属性a和print方法,但是由于它们都和MyC中的属性和方法同名,
//print方法被覆盖,a被隐藏,并且值编程默认值0
class MyC extends MyB {
int a = 3;
public MyC() { //2)做print();之前默认调用MyB(),MyB()又默认调用MyA(),
//3)调用父类构造时,做的是子类的print(),打印的a是自己的,不过,对于父类的是默认值0,子类的还是原始只
print();
}
public void print() {
System.out.println("ccc" + a);
}
}public class Main {
public static void main(String[] args) {
new MyC();// 1).调用构造MyC();
}
}
int a = 1;
MyA(){
printA();
}
void printA(){
System.out.println("MyA"+a);
}
}class MyB extends MyA{
int a=2;
MyB(){
printB();
}
void printB(){ //重写了MyA类的print()方法
System.out.println("MyB"+a);
}
}class MyC extends MyB{
int a = 3 ;
MyC(){
printC();
}
void printC(){ //重写了MyB类的print()方法
System.out.println("MyC"+a);
}
}
//////
public class MyClass{
public static void main(String[] args){
new MyC();
}
}说明几下:再重复一下,先调用超类的构造函数,所以就调用MyA 类,而MyB类的print()
方法覆盖了超类MyA类的print()方法;MyC类雷同……
所以,当你New Myc的时候,总是调用自己的print()方法.
为什么刚开始两个是0呢?那是因为程序先执行的是new MyC();还没有执行int a = 3;
也就是执行完了两个超类的构造函数后,才执行了自己的构造函数,所以最后一个打出来的
是3.我上面的程序取消了子类重写父类的print方法,所以结果正是Lz期望的.结果为:
MyA1
MyB2
MyC3