JavaSE传送门
JavaSE_Start
JavaSE-No.6.2——封装与static
JavaSE-No.6.3——代码块与内部类
注:
关于继承将分成两篇文章讲解,那我们就开始吧~
目录
1. 为什么需要继承
Java
中使用类对现实世界中实体来进行描述,事物之间可能会存在一些关联,那在设计程序时就需要考虑。
例如: 猫和狗,他们都是动物。
我们分别来定义一个
猫类
和一个
狗类
:
classDog{publicString name;publicint age;publicString color;publicvoideat(){System.out.println(name+"正在吃饭!");}publicvoidwalk(){System.out.println(name+"正在和主人散步。");}}classCat{publicString name;publicint age;publicString color;publicvoideat(){System.out.println(name+"正在吃饭!");}publicvoidplay(){System.out.println(name+"正在玩球。");}}
我们对比一下,发现两个类有一些相同的成员与方法。
那能否将这些
共性抽取
呢?面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。
2. 继承的概念
那么什么是继承呢?
继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。
简单来说就是将他们的共性进行抽取,把抽取出来的共性放到一个类当中,我们创建一个
Animal
类:
classAnimal{publicString name;publicint age;publicString color;publicvoideat(){System.out.println(name+"正在吃饭!");}}
这时我们会发现
Dog
类和
Cat
类都报错了,怎么才能让Dog和Cat类访问到name呢?
2.1 继承的语法
这时我们要用到
extends
关键字:
修饰符 class 子类 extends 父类 {// ... }
更改
Dog
和
Cat
类
classDogextendsAnimal{publicvoidwalk(){System.out.println(name+"正在和主人散步。");}}classCatextendsAnimal{publicvoidplay(){System.out.println(name+"正在玩球。");}}
我们再来简单解释一下,此处我们的
Dog
又被称为:子类、派生类;
Animal
被称为:父类、基类、超类。
我们在主函数中实例化一个
dog
publicclassTest{publicstaticvoidmain(String[] args){Dog dog =newDog();
dog.name ="修勾";
dog.age =6;
dog.color ="white";
dog.eat();
dog.walk();}}
总结:
- 子类会将父类中的成员变量或者成员方法
继承
到子类中了 - 子类继承父类之后,
必须
要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了
3 父类成员的访问
3.1 子类访问父类的成员变量和成员方法
子类和父类不存在同名成员变量或成员方法
classBase{publicint a =1;publicint b =2;publicvoidfunc1(){System.out.println("父类中func1方法");}}classDerivedextendsBase{publicint c =3;publicint d =4;publicvoidfunc2(){System.out.println("子类中func2方法");}publicvoidfunc(){System.out.println(this.a);//访问从父类中继承下来的a,bSystem.out.println(this.b);System.out.println(this.c);//访问子类自己的c,dSystem.out.println(this.d);this.func1();//调用父类中继承的func1()方法this.func2();//调用子类中继承的func2()方法}}
子类和父类成员变量或成员方法同名
classBase{publicint a =1;publicint b =2;publicvoidfunc1(){System.out.println("父类中func1方法");}}classDerivedextendsBase{publicint a =11;publicint b =22;publicvoidfunc1(int n){System.out.println("子类中func1方法(n)");}publicvoidfunc1(){System.out.println("子类中func1方法");}publicvoidfunc(){System.out.println(this.a);//输出什么??System.out.println(this.b);this.func1();//输出什么??this.func1(1);}}
我们思考一下,此时会输出
1、2
,还是
11、12
?会运行父类中的func1还是子类中的func1?
答:11 12,子类中的func1。如果访问的成员变量或成员方法与父类中
的同名
,则优先访问自己的。
运行结果展示:
**
# 注意事项 #
**
- 如果访问的成员变量子类中有,优先访问自己的成员变量。如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
- 如果访问的成员变量与父类中成员变量
同名
,则优先访问自己的。 - 如果访问父类与子类中
不同名方法
时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。 - 如果访问父类与子类
同名方法
时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;
3.2 super关键字
如果我们想要在子类父类成员变量和成员方法同名的情况下,想在子类中访问父类这时我们就要用到super关键字
publicvoidfunc(){System.out.println(this.a);//访问子类中的a,bSystem.out.println(this.b);System.out.println(super.a);//访问父类中的a,bSystem.out.println(super.b);this.func1();//调用子类中的func1方法super.func1();//调用夫类中的func1方法}
运行结果展示:
**
# 注意事项 #
**
- 只能在
非静态方法
中使用 - 在子类方法中,访问
父类
的成员变量和方法。 super
指代的是子类从父类继承过来的内容这块空间的地址
。super();
调用父类的构造方法,接下来就讲到。
4. 子类构造方法
我们回到
Animal
和
Dog
类中,我们现在想给
Anima
l提供一个构造方法:
classAnimal{publicString name;publicint age;publicString color;//新增构造方法publicAnimal(String name,int age,String color){this.name = name;this.age = age;this.color = color;}publicvoideat(){System.out.println(name+"正在吃饭!");}}
这时我们发现,
# Dog类报错了 #
,我们将其屏蔽,Dog类没有报错。
那么这是为什么呢?
父子父子,先有父再有子,即:子类对象构造时,需要先调用父类构造方法,然后执行子类的构造方法。
我们这里就要在子类的构造中,先对父类进行初始化。
classDogextendsAnimal{//构造方法publicDog(String name,int age,String color){super(name, age, color);//显示的调用父类的构造函数,来初始化此时子类继承过来的父类的属性}publicvoidwalk(){System.out.println(name+"正在和主人散步。");}}
**
# 注意 #
** super();只能在子类构造方法的
第一行
。
idea生成
为什么一开始没有写任何构造函数的时候也没有报错呢?
在我们在父类和子类中没有写构造方法时,编译器默认在父类和子类中提供构造方法。
例如:在Animal类中提供
publicAnimal(){}
在Dog类中提供
publicDog(){super();}
总结:****子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。
**
# 注意事项 #
**
- 若父类显式定义
无参
或者默认
的构造方法,在子类构造方法第一行默认有隐含
的super()
调用 - 如果父类构造方法
只有一个
是带有参数的,此时编译器不会
再给子类生成默认的构造方法,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。 - 在子类构造方法中,
super(...)
调用父类构造时,必须是子类构造函数中第一条
语句。 super(...)
只能在子类构造方法中出现一次
,并且不能和this
同时出现
5. super和this的比较
相同点
- 只能在类的
非静态方法
中使用,用来访问非静态成员方法和字段 - 在构造方法中调用时,必须是构造方法中的
第一条语句
,并且不能同时存在
不同点
thissuper\当前对象的引用,当前对象即调用实例方法的对象子类对象中从父类继承下来部分成员的引用非静态成员方法访问本类的方法和属性访问父类继承下来的方法和属性非静态成员方法是一个隐藏参数不是隐藏的参数构造方法调用本类构造方法调用父类构造方法构造方法中
this(...)
用户不写编译器不会自动生成一定会存在
super(...)
的调用,用户没有写编译器也会增加
🌷(( ◞•̀д•́)◞⚔◟(•̀д•́◟ ))🌷
以上就是今天要讲的内容了,希望对大家有所帮助,如果有问题欢迎评论指出,会积极改正!!关于继承相关的知识还没有结束,下一篇文章会继续讲述,期待大家支持,谢谢~
版权归原作者 Gujiu!! 所有, 如有侵权,请联系我们删除。