class Parent{
int x=10;
public Parent(){
add(2);
}
void add(int y){
x+=y;
}
}
class Child extends Parent{
int x=9;
void add(int y){
x+=y;
}
public static void main(String[] args){
Parent p=new Child();
System.out.println(p.x);
}
}
问输出结果是什么?
答案应该是10。
要理解结果为什么是10,需要首先明白下面的知识:
(1)方法和变量在继承时的隐藏与覆盖
隐藏:若B隐藏了A的变量或方法,那么B不能访问A被隐藏的变量或方法,但将B转换成A后可以访问A被隐藏的变量或者方法。
覆盖:若B覆盖了A的变量或者方法,那么不仅B不能访问A被覆盖的变量或者方法,将B转换成A后同样不能访问A被覆盖的变量或者方法。
(2)Java中变量与方法在继承中的隐藏与覆盖规则:
一、父类的实例变量和类变量能被子类的同名变量隐藏。
二、父类的静态方法被子类的同名静态方法隐藏,父类的实例方法被子类的同名实例方法覆盖。
三、不能用子类的静态方法隐藏父类的实例方法,也不能用子类的实例方法覆盖父类的静态方法,否则编译器会异常。
四、用final关键字修饰的最终方法不能被覆盖。
五、变量只能被隐藏不会被覆盖,子类的实例变量可以隐藏父类的类变量,子类的类变量也可以隐藏父类的实例变量。
在上面的试题中,子类Child的实例方法add(int y)覆盖了父类Parent的实例方法add(int y),而子类的实例变量x则是隐藏了父类的实例变量x。
Child对象的初始化过程是:
首先为父类的实例变量x分配内存空间,因为在定义变量x时为它赋了值(int x=10),所以会同时将这个值赋给x。
其次调用父类的无参构造函数,Parent的构造函数中做的唯一的事情就是调用了add(2);
第三、由于子类的add(int y)方法覆盖了父类的方法,所以add(2)实际调用的是子类的方法,在子类的add方法中做了如下操作x+=j;在这里由于子类的实例变量x隐藏了父类 的实例变量x,所以这条语句是针对子类本身的,但是这时还没有为子类的实力变量x分配空间,它的默认值是0,加2之后是2。
第四、父类初始化完毕后接着初始化子类,为子类的x分配内存空间并将它赋值为9,之前的add(2)操作白瞎了。
再次注意Parent p=new Child();这条语句,它是用父类的引用指向子类的对象,而前面已经说过变量只会被隐藏不会被覆盖,所以这时的p.x值应该是父类的10,而不是子类的9;
如果将输出语句换成下面的语句结果就是9了:
System.out..println(((Child)p).x); //首先将p转换成Child类型
分享到:
相关推荐
主要介绍了c++ 子类构造函数初始化及父类构造初始化的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
java 静态_非静态 字段_方法_代码块 子类父类构造_初始化顺序! 三个class 让你清清楚楚 第一个class java代码如下: package initialOrder; class Parent { // 静态变量 public static String p_StaticField...
NULL 博文链接:https://happywaterlife.iteye.com/blog/1567461
主要介绍了Python实现子类调用父类的初始化实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
本文实例讲述了Python实现...子类不显式调用父类的构造方法,而父类构造函数初始化了一些属性,就会出现问题 如果子类和父类都有构造函数,子类其实是重写了父类的构造函数,如果不显式调用父类构造函数,父类的构造
——学习参考资料:仅用于个人学习使用! 本代码仅作学习交流,切勿用于商业用途,否则后果自负。若涉及侵权,请联系,会尽快处理! 未进行详尽测试,请自行调试!
本篇文章是对java父类和子类初始化顺序进行了详细的分析介绍,需要的朋友参考下
主要介绍了C#中子类调用父类的实现方法,通过实例逐步分析了类中初始化构造函数的执行顺序问题,有助于加深对C#面向对象程序设计的理解,需要的朋友可以参考下
主要介绍了python类继承与子类实例初始化用法,实例分析了Python类的使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
当子类继承父类后,需要调用父类的方法和属性时,需要调用父类的初始化函数。 class A(object): def __init__(self): self.nameaa = 'aa' def funca(self): print('function a %s' % self.nameaa) class B(A): ...
时间久了就容易记不清了,特留存备用查看 ...—–基类无/有默认构造函数时,在子类构造函数初始化列表处调用,则显示调用 基类类名(参数) class Base { public: Base(int b) : m_b(b) { } private: int m_b
前面我们学习了C++使用初始化列表的方式来初始化字段的方法: https://www.jb51.net/article/153032.htm 这一节的原理和前面的差不多。 在C++的构造函数中,子类继承父类,那么,在创建一个子类成员时,可以同时向...
构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统...
用简单几句话说明java成员初始化顺序,适合初学者
子类初始化前,会先加载并初始化它的父类 初始化一个类,其实质上就是执行了()方法 ()方法包含了,静态变量显式赋值代码以及静态代码块 静态变量显式赋值代码以及静态代码块的执行顺序,由它们的先后顺序执行,先...
这里直接给出C#类成员一般初始化顺序: 子类静态字段 子类静态构造 子类实例字段 父类静态字段 父类静态构造 父类实例字段 父类实例构造 子类实例构造 为什么说是“一般”初始化顺序呢?因为根据类结构的...
所以父类和子类的初始化方式都是__init__(),但是如果子类初始化时没有这个函数,那么它便调用父类的__init__();如果实现了这个函数,就会覆盖父类的初始化函数。如果继承父类的__init__(),就需要在子类中显示调用...
构造函数的基本作用是创建对象,还可以初始化对象。 函数的类型和函数的参数个数不一样才能重载 子类继承父类以后,当子类创建对象时先调用父类的构造函数再调用子类的构造函数,删除对象时先调用子类的析构函数再...