成员变量:
先看这样一段代码:
//父类。 class Fu { int num = 3; } class Zi extends Fu { int num = 4; void show() { System.out.println("num = "+this.num); } } class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
从一张图来看它的原理:
图有点乱,看一下顺序吧。在代码中,super和this 的用法很相似,this代表的是本类对象的引用,super代表的是父类的内存空间。
成员函数:
【子父类中成员函数的特点】
特殊情况:子父类中的定义了一模一样的函数。
运行的结果:子类的函数在运行。
这种情况在子父类中,是函数的另一个特性:override(重写,覆盖,复写)
重写什么时候用?举例:
//描述手机。 class Phone { int number; //打电话。 void call(){} //来电显示。 void show() { sop("电话号码.."+number); } } Phone p = new Phone(); p.show(); 随着电话的升级,只显示号码不爽,希望显示姓名,照片。 修改源码,虽然费劲但是可以解决,不利于后期的维护和扩展。 为了扩展方便。新功能是不是新的电话具备呢? 单独描述单独封装。新电话也是电话中的一种。继承。直接获取父类中的功能。 但是新电话的来显功能已经变化了。需要重新定义。 那么定义一个新功能合适吗?比如newShow,不合适,因为父类已经将来显功能定义完了, 子类完全不需要重新定义新功能。直接用就可以了。如果子类的来显功能内容不同。 直需要保留来显功能,定义子类的内容即可:这就是重写的应用! class NewPhone extends Phone { String name; String picPath;//图片路径。 void show() { //sop("电话号码"); super.show();//如果还需要父类中原有的部分功能,可以通过super调用。 System.out.print("姓名"+name); System.out.print("照片"+picPath); } }
【重写(覆盖)的注意事项】
1,子类覆盖父类,必须保证全要大于或者等于父类的权限。
Fu:
private void show(){}
Zi:
public void show(){}
2,静态覆盖静态。
写法上稍微注意:必须一模一样:函数的返回值类型 函数名 参数列表都要一样。
【总结】
当一个类是另一个类中的一种时,可以通过继承,来扩展功能。
如果从父类具备的功能内容需要子类特殊定义时,使用重写。
++【子父类中构造函数的特点】
当子父类都有构造函数时,发现结果为:
fu constructor run
zi constructor run
先执行了父类的构造函数,再执行子类的构造函数。
【这是为啥呢?】
因为子类的所有的构造函数中的第一行都有一句隐式语句 super(); //默认调用的是父类中的空参数的构造函数。
【子类中的构造函数为什么有一句隐式的super()呢?】
原因:子类会继承父类中的内容,所以子类在初始化时,必须先到父类中去执行父类的初始化动作。
才可以更方便的使用父类中的内容。
【小结】
当父类中没有空参数构造函数时,子类的构造函数必须同构显示的super语句指定要访问的父类中的构造函数。
这就是传说中的子类实例化过程。
【实例化过程的细节】
1,如果子类的构造函数第一行写了this调用了本类其他构造函数,那么super调用父类的语句就没有了,因为this()或者super(),只能定义在构造函数的第一行,因为初始化动作要先执行。
2,父类构造函数中是否有隐式的super呢?
有。记住:只要是构造函数默认第一行都是super();
父类的父类是谁呢?super调用的到底是谁的构造函数呢?
Java体系在设计,定义了一个所有对象的父类Object ,
【总结】
类中的构造函数默认第一行都有隐式的super()语句,在访问父类中的构造函数。
所以父类的构造函数既可以给自己的对象初始化,也可以给自己的子类对象初始化。
如果默认的隐式super语句没有对应的构造函数,必须在构造函数中通过this或者super的形式明确调用的构造函数。
【问题】
1,this语句和super语句是否可以在同一个构造函数中出现呢?不行,因为必须定义在第一行。
2,为什么要定义在第一行呢?因为初始化动作要先执行。