public class Apple extends Fruit {
private String name = "apple";
public Apple () {
tellName();
printName();
}
public void tellName() {
System.out.println("Apple tell name: " + name);
}
public void printName() {
System.out.println("Apple print name: " + name);
}
public static void main(String[] args){
new Apple();
}
}
class Fruit {
private String name = "fruit";
public Fruit () {
tellName();
printName();
}
public void tellName() {
System.out.println("fruit tell name: " + name);
}
public void printName() {
System.out.println("fruit print name: " + name);
}
}
我想知道为什么会输出4行
以及什么原因
感谢各位
1.先走第三行代码进tellName()方法。打印输出 Apple tell name: null
2.进入Class Fruit 进入public Fruit()方法中的tellName
3.再走第三行代码进printName()方法。打印输出 Apple print name: null
4.进入Class Fruit 进入public Fruit()方法中的printName
5.走第二行代码 给name赋值apple
6.重复走1-打印输出 Apple tell name: apple -2-3 -打印输出 Apple print name:apple
我觉得在继承的时候就默认调用了父类的构造方法。所以会多出两行。这就好比你继承Jbutton。就算你啥都不写调用之后还是会显示一个button。个人理解。错了勿喷
应该是调用了父类的构造方法,你可以把父类的构造方法里面的方法注释掉一个看下效果
创建子类实体时,在执行构造方法时会先执行父类的构造方法,所以会先输出父类的两行,在输入子类的两行
实例化子类对象时,父类对象也会相应的被实例化,也就是说实例化子类对象时,Java编译器会在子类的构造方法中调用父类的的**无参构造函数**。
继承并不继承构造,其他构造方法什么的都继承,而父类的两个方法在子类中重写。所以实际上就只有子类的两个方法。
注释掉父类构造里面的方法就出现只有两个结果的情况,可以说明执行父类构造的时候调用了子类的方法,但是并没法传递name值,所以为空。
大家可以试试把父类中的两个狗杂哦方法改为private类型,这样不满足继承中重写条件,那么执行父类构造时只会调用父类方法值不为空。吓试的不一定正确,求改
http://blog.csdn.net/u012768347/article/details/51009724
当创建一个子类实例时,在对象初始化过程中会依据继承体系向上初始化父类。
其实在子类构造器其中,有一个隐式语句是Java虚拟机自动加上的,比如在Apple类默认构造函数的第一句,有super();
这样会先初始化Fruit类,所以有输出
java新手,亲手试验补充,实践证明父类的name属性即使是public结果一样;顺序如数字所标从大到小,若父类中的name属性为private则跳过4
public class Apple extends Fruit {
private String name = "apple";//9
public Apple () {//2
tellName();//10
printName();//12
}
public void tellName() {//6 //11
System.out.println("Apple tell name: " + name);
}
public void printName() {//8 //13
System.out.println("Apple print name: " + name);
}
public static void main(String[] args){
new Apple(); //1
}
}
class Fruit {
public String name = "fruit";//4
public Fruit () {//3
tellName();//5
printName();//7
}
public void tellName() {
System.out.println("fruit tell name: " + name);
}
public void printName() {
System.out.println("fruit print name: " + name);
}
}
这个问题在Thinking in java中有比较好的一个解释,我们要知道在new子类对象的过程中发生了些什么:
1、在其他任何事物发生之前,将分配给对象的存储空间初始化为二进制的零,也就是说,我现在要new Apple对象了,我先要分配好内存,而且内存全部初始化为0
2、调用基类构造器。子类构造器在调用的时候必须调用基类的构造器(有可能你没写,也成功了,那是因为java默认帮你调用了,但是最好还是自己显式写出来)
重点就在于第二步:在这个例子里面,Fruit的构造器调用了tellName(),printName().而子类又重写了这两个方法,所以在这里就已经存在了多态。因为在加载类的
时候发现我的子类已经重写了这两个方法,所以基类中的tellName(),printName()实际上是子类重写之后的方法。所以执行代码你会发现,前两行输出的是
Apple tell name: null
Apple print name: null
说明这个方法是子类的方法,而不是基类的
至于为什么是null:因为这里的name指向的是子类的私有成员name,而这个时候子类的私有成员还没有被初始化,只有父类的私有成员name被初始化了
所以这里当然显示null
3、按照声明的顺序调用成员的初始化方法。执行完父类的构造方法,才会转到子类对子类的name进行初始化,这也解释了null的问题。
4、调用子类的构造方法。这个时候再调用子类的构造方法,这时候因为name已经初始化了name="Apple"。所以这时候显示的就是
Apple tell name: apple
Apple print name: apple
总结:这个问题的关键就是,如果基类的构造器调用了基类的方法,而恰好这个方法又被子类重写了,那么实际上基类构造器在执行的时候
是执行的子类重写后的方法。
因为这样的特性,有时会导致很多问题,所以建议构造方法里面的内容要尽可能简单,构造器里面唯一能安全调用的方法是基类中的final方法,
因为它们不会被重写。
new子类时会走父类的构造方法,再走自己的构造,所有一共就是4行啦
创建子类对象时候会默认调用系统的无参数构造器,也就是fruit类中的无参数构造器,fruit的无参数构造器里面调用了两个他的方法,这两个方法会先执行,然后执行Apple的无参数构造器,Apple的无参数构造器里面调用了他自己的两个方法,因此就会执行这两个方法
不好意思,刚才打错字了,第一句是 创建子类对象时候会默认调用父类的无参数构造器