从零开始学Java【18】
从零开始学Java【18】
学习视频:https://www.bilibili.com/video/BV12J41137hu?p=68
什么是继承

继承的本质是对一批类的抽象,意思是在原有抽象的基础上再抽象。比如一个具体的人,可以用亚洲人来抽象,而地球上有亚洲人,欧洲人和其它人种,都抽象为一个大类:人类。
如下面例子。定义一个类:Person类,再定义两个Student和Teacher类,继承Person类

这三个类,就是有着继承的关系,除此以外,类与类的关系还有依赖,组合,聚合这些以后再说。
继承有个特点,那就是子类继承者父类的所有方法。

可以看到,子类没有任何东西,但是实例化对象之后却可以执行父类的方法,以及显示父类的属性
参考链接:https://www.csdn.net/tags/OtDaIgxsNzUyNC1ibG9n.html


按照查找关系来返回信息:比如定义一个爷类,一个父类,一个子类,输出子类.XXX,则查找的优先级是子类,子类有的就直接输出子类的不用管父类爷类,如果子类没有就找父类有没有,如果没有再找爷类。
而一般来说,很多类中的属性都是私有的,通过get,set方法来和外界取得联系,改进之后:

这样就是封装之后的了,更加严谨。
查看类的结构关系快捷键:CTRL+H

鼠标光标在类的代码里面点一点,再ctrl+h,会显示当前类的结构关系

Object类
所有的类都直接或者间接继承Object类,可以理解Object是所有类的祖宗,所有类都可以用它的方法。
而学习Object类要贯穿Java的整个学习过程,所以目前先把它看成一个祖宗类,比如上图Person,其实就是默认继承Object类的
super
super表示的是当前类的父类,而this表示的是当前类。

- 关于属性。可以看到,当新建一个学生类对象,然后使用学生类的test方法,输入实参“小黄”,那么首先输出“name”所指代的实参输入name,再输出“this.name”所指代的当前类的属性,再输出“super.name”所指代的当前类的父类的属性。

- 关于方法。可以看到,当新建一个学生类对象,然后使用学生类的test方法,首先“print”方法是执行当前类的“print”方法,再执行“this.print”,执行当前类方法,再执行“super.print”,执行当前类的父类方法。另:当父类的方法变成私有private时,那么在子类用super是调用不了父类的。

- 关于构造器的构造方法。前面所讲,其实new一个对象出来,new其实就是执行构造器里面的内容,如果没有有参构造器的话就执行无参构造器。可以看到,首先执行Student里面的无参构造器,但是从输出界面可以看到,父类的无参构造器也执行了,说明子类的无参构造器里面,是默认执行一个方法的:super()。如下图:

这段隐藏代码,就算不写,它也是会有的。注:super()即为调用父类的构造函数,this()即为调用子类的构造函数。
关于上图所说的隐藏代码:super()注意:
- super()或者this()必须在构造函数的第一行,是不能放到其它代码下面的,否则会报错。调用父类构造器,必须要在子类构造器的第一行。


2.super()和this()是不可以同时出现的,因为要么调用子类构造器,要么调用父类构造器
3.这里就可以延伸到上节课说的一个概念:为什么一个类在写有参构造的时候一定要有无参构造呢?(虽然说一个类写了有参构造如果偏不写无参构造,可能系统有时候不会报错),这里可以结合一个类总是会在无参构造器中隐藏一个super()函数结合解释了。如果父类只有有参构造器而没有无参构造器,那么可以看到,子类的无参构造器就开始报错:

因为子类的无参构造首先隐藏代码调用的就是父类的无参构造。如果父类没有无参构造,则会报错,所以写了有参之后一定要把无参构造显化。其实也有解决办法,在这里只要子类中调用父类的有参构造就可以了,如图:

此处调用父类的有参构造,问题就解决了。当然,按照编程习惯,写上有参构造的时候一定要加上无参构造最好了。
总结
super注意点:
- super调用父类的构造方法,必须在构造方法的第一行
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
this与super的比较:
- this:本身调用这个对象
- super代表父类对象的应用
- this在没有继承的条件下可以使用
- super只能在继承条件下才可以使用
- 构造方法说的是super(),this(),意思就是访问父类或者子类的构造方法
方法重写
重写是方法的重写,和属性无关。

这里出现了:
//方法的调用只和左边定义的数据类型有关
A a = new A();
a.test();
B b = new A();//父类的引用指向了子类
b.test();
其中B b = new A();是父类的引用指向了子类,这样是可以的,因为A和B是继承关系,所以类型是可以转换的,这种叫做向上转型,这方面是和多态有关系的,先了解一下。
则输出为:
A=>test()
B=>test()
可以看到一个规律,那就是类型只和左边有关,比如B b = new A()其实就是B类型的。
得出一个结论:方法的调用只和左边定义的数据类型有关。
所以当执行b.test()的时候,这个b是B类型的,所以执行B类型的方法。目前阶段先了解到这里,这里到后面多态会讲的。
然后把A和B中的方法把静态static去掉,可以发现不一样,输出结果为:

A=>test()
A=>test()
可以得出一个结论:静态方法和非静态方法区别很大。所以前面的那个结论:方法的调用只和左边定义的数据类型有关,这个表述是还不够全面的,因为没有考虑静态和非静态的情况。
由两个结果的不同,可以得出这么一个结论:因为static是和类一起加载的,非static是需要对象的。所以,静态方法是类的方法,而非静态方法是对象的方法。那么下面这个语句:
B b = new A();
有static时,b调用了B类的方法,因为b是用B类来定义的(静态方法是类的方法)
没有static时,b调用的时对象的方法,而b是用A类new出来的,是A类的对象。Java中是用new来创建对象的,这里把new创建的对象赋予了b,所以此时的b在没有static时看的是对象,即看的是new创建的对象是什么。
所以再进阶一点的结论就是:有static看左边,没有static看右边。即有static看类型,没有static看对象。
此时,弄清楚了语句之后,再返回来看看去掉static的这张图,下面说一下图中的重写:

上图中,A中的方法是对B的方法的重写(重载是改变参数,重写是对方法体的重写),所以能看到旁边有箭头,点击箭头,就可以跳转到重写的方法位置了:

注:可以使用alt+insert进行重写,重写之后出现Override,即为重写的意思

而由@开头的英文是一个有功能的注释,将再以后的注解与反射学习到。
使用快捷键之后,可以看到重写的这个方法默认是调用父类的方法的,之后就可以根据自己的需要来重写方法了:

结果和之前的一样
那么图中,可以观察到,在非静态的情况中,子类重写了父类的方法。所以重写这种情况只有在继承这种状态下才可能出现。
在重写的过程中要注意,不能对private的方法进行重写,只能对public,protected和default方法重写。
对于重写的总结
前提:需要有继承的关系,子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符范围可以扩大不可以缩小。比如A类继承了B类,重写B类的方法,父类B类的方法是private的,那么子类的重写方法可以是public,就把范围扩大了(public > Protected >Default > private)
- 抛出的异常范围可以被缩小不能被扩大。这个概念先记着,后面异常会讲到。举个例子,比如父类欠了人家50块钱,当子类继承的时候,总不能越欠越多吧,肯定得还一点点钱才行。关于异常大小的话举个例子:Class NotFoundException是一个小异常,Exception是一个大异常。其他的后面学到异常了再说吧。
总的来说,子类的方法名字必须和父类名字相同,只是方法体不同。
为什么需要重写?
- 父类的功能,子类不一定需要,或者不一定满足。后代继承前代的东西,肯定根据自己的需要取其精华剔除糟粕来继承嘛,有用的就留下来,没有用的就需要,还有自己有的前代没有的也可以。
重写快捷键
alt+insert,选择方法即可重写


浙公网安备 33010602011771号