Java学习笔记13.——面向对象进阶之继承
文章目录
前言
Java中三大特性,封装,继承,多态。
之前学了封装的知识点,对象代表什么,就得封装对应的数据,并提供封装数据对应的行为。
今天学习继承的知识点。
一、继承
1.继承是什么?
假设
当学生类中有姓名属性,性别属性,年龄属性,学习方法,吃饭方法,set/get方法
当老师类中有姓名属性,性别属性,年龄属性,教书方法,吃饭方法,set/get方法
如果自己编写会发现代码重复度太高了,这样不利于节省时间。
这时候就可以设计一种东西,把重复的代码提出来,然后去继承这些重复的代码,并添加上不重复的方法。
假设提出来的公共代码有姓名属性,性别属性,年龄属性,吃饭方法,set/get方法
Java中使用extends关键字来实现继承
具体使用情况如下:
public class Student extends Person{}
这时候Student类之间继承了Person中的所有属性和方法,并且Student类中还可以加上学生的学习方法。
此时的学生类就是子类(派生类),Person就是父类(基类或超类)
2.继承的好处
1.父类中的都是重复性高的属性和方法,子类继承可以提高代码的复用性
2.子类可以在父类上增加其他功能,使子类更加强大
3.什么时候使用继承
当类与类之间具有共性(相同)代码时,且满足子类是父类的一种东西,就可以使用继承来优化代码。
比如学生类满足Person(人类)类,老师也满足人类就可以使用。
如果学生有id,名字,成绩和手机有id,名字,价格。虽然id,名字是相同的,但是类不属于同一个东西。学生是人,手机是商品不能混为一谈这种就不能使用继承。
4.继承的特点
Java只支持单继承,不支持多继承,但支持多层继承
只支持单继承:一个子类只能有一个父类,一个儿子只能有一个爸爸
不支持多继承:一个子类只能有一个父类,不能有多个父类。一个儿子不能有多个父亲
支持多层继承:一个子类继承了父类,该父类又继承了一个类。这里子类和父类2的关系还是父子类关系。
但是不代表没有继承的类就不是子类了。
每一个类都间接或直接的基础object类。
这是由虚拟机进行的,如果该类没有被继承就会继承object类,那继承了的类就属于间接继承object类,因为父类会直接继承object类。
注意:父类的私有修饰的不能被访问
因为父亲的私房钱你不能使用。
所以子类能继承父类中非私有的属性和方法。
5.继承练习
题目
现在有四种动物:布偶猫、中国狸花猫、哈士奇、泰迪。暂时不考虑属性,只要考虑行为。
请按照继承的思想特点进行继承体系的设计。
四种动物分别有以下的行为:
布偶猫:吃饭、喝水、抓老鼠中国狸花猫:吃饭、喝水、抓老鼠哈士奇:吃饭、喝水、看家、拆家泰迪:吃饭、喝水、看家、蹭一蹭
第一步分析
从下往上分析
第二步敲代码,从上往下
package a02StaticDemo3.cat;
public class Test {
public static void main(String[] args) {
Teddy teddy = new Teddy();
teddy.eat();
teddy.drink();
teddy.LookingHome();
teddy.sajiao();
System.out.println("-------------------------");
buou buou = new buou();
buou.eat();
buou.drink();
buou.CatingMice();
}
}
6.子类到底能继承父类中的哪些内容?
一个类中包含三个部分
构造方法 | 非私有 不能继承 | 私有private 不能继承 |
---|---|---|
成员变量 | 非私有 能继承 | 私有private 能继承 |
成员方法 | 非私有 能继承 | 私有private 不能继承 |
1.构造方法
一旦构造方法可以继承,那么就违背了构造方法的定义所以不管私有不私有,构造方法都不难继承
2.成员变量
虽然成员变量私有的可以继承,但是就像上了锁的箱子不能直接使用。
钥匙就是get/set方法
3.成员方法
我这是在给我自己做笔记,直接粘贴复制。
累加虚方法,实际上就是一个空间装下这些方法方便使用。所有的设计不过都是为了更好的使用,如果有冗余那就是设计得不够完美或者有东西没有考虑完全。
成员方法里面的方法里:
非private 非static 非final 修饰的方法就可以进入虚方发表中。
阿伟老师的PPT做得太好了,爱了爱了。
加载字节码文件时发现zi类还有父类就加载fu字节码文件,因为所有没有继承的类都继承object类,所以object类进入方法区。堆内容中,右边是子类的成员变量,左边是父类的成员变量。
二、特点
1.成员变量的特点
特点:就近原则
先在局部变量寻找,本类寻找,然后父类逐层往上
如果成员变量同名,那么就可以这样。
package a02StaticDemo3.Test;
public class Test2 {
public static void main(String[] args) {
Zi z = new Zi();
z.Name();
}
}
class Ye{
String name = "ye";
}
class Fu2 extends Ye{
// String name = "Fu";
}
class Zi extends Fu2{
String name = "Zi";
public void Name(){
String name = "ZiShow";
System.out.println(name);//ZiShow
System.out.println(this.name);//Zi
System.out.println(super.name);//ye,如果Fu2没被注释这里输出的就是Fu
}
}
super只能代表父类(间接,直接),不能叠加super比如
super.super.name;
2.成员方法的特点
特点:就近原则
public class Test3 {
public static void main(String[] args) {
OverseasStudent s = new OverseasStudent();
s.eat();
s.drink();
}
}
class Person{
public void eat(){
System.out.println("吃米饭,用筷子");
}
public void drink(){
System.out.println("喝水");
}
}
class OverseasStudent extends Person{
public void eat(){
System.out.println("吃面包,用刀叉");
}
public void drink(){
System.out.println("喝凉水");
}
}
运行结果
吃面包,用刀叉
喝凉水
这是方法重写
方法重写
当父类的方法不能满足子类需求的时候,就进行方法重写。
类似于刚才那样
格式:
子类中出现了和父类一样的方法声明时就称子类这个方法是重写的方法。
重写注意
1.重写方法前面加上@Override,这个是检验重写格式是否正确。
2.只有虚方法表中的方法才可以被重写(静态,私有,final不是)
3.子类重写的权限要大于等于父类的权限(空中不写<Protection<Public)
4.子类重写的返回值类型必须小于等于父类
5.子类重写的参数名列表要保持一致
(建议重写的方法和父类尽量保持一致)
重写本质
前面写过虚方法表,当B继承了C类的虚方法表时,重写了方法就是覆盖了虚方法表中的一个方法。
重写的本质就是覆盖虚方法,如果查找C类中的虚方法则是没有被覆盖的,查找B类中的虚方法则是被覆盖过的。
重写小练习
现在有三种动物:哈士奇、沙皮狗、中华田园犬暂时不考虑属性,只要考虑行为。
请按照继承的思想特点进行继承体系的设计。
三种动物分别有以下的行为:
- 哈士奇:
吃饭(吃狗粮)、
喝水、看家、拆家 - 沙皮狗:
吃饭(吃狗粮、吃骨头)、
喝水、看家 - 中华田园犬:
吃饭(吃剩饭)、
喝水、看家
package a02StaticDemo3.Test;
public class DogTest {
public static void main(String[] args) {
Husky h = new Husky();
h.eat();
h.drink();
h.lookHome();
h.breakHome();
System.out.println("-------------------------");
Sharpi s = new Sharpi();
s.eat();
s.drink();
s.lookHome();
System.out.println("-------------------------");
ChinaDog c = new ChinaDog();
c.eat();
c.drink();
c.lookHome();
}
}
class Dog{
public void eat(){
System.out.println("吃狗粮");
}
public void drink(){
System.out.println("喝水");
}
public void lookHome(){
System.out.println("看家");
}
}
class Husky extends Dog{
public void breakHome(){
System.out.println("拆家");
}
}
class Sharpi extends Dog{
@Override
public void eat(){
System.out.println("吃狗粮,吃骨头");
}
}
class ChinaDog extends Dog{
@Override
public void eat(){
System.out.println("吃剩饭");
}
}
3.构造方法的特点
构造方法不能被继承,但是子类的构造方法会先调用父类的无参构造方法。
因为子类初始化的时候可能会使用父类中的数据,如果父类中的数据没有初始化那么子类也不能初始化成功。
所以子类中初始化之前一定要调用父类构造方法完成父类数据空间的初始化。
使用super调用父类的构造方法,不写也存在(写在子类构造方法中的第一行)
如果想调用父类中的有参构造,那么就需要使用super手动调用
- 子类不能继承父类的构造方法,可以使用super调用
- 子类中构造方法中的第一行默认是super()
- 子类默认调用父类中的无参构造方法再执行自己
- 子类调用父类有参构造方法时需要使用super
package a02StaticDemo3.Test;
public class Test4 {
public static void main(String[] args) {
Students s = new Students();
Students s2 = new Students("zhangsna",24);
System.out.println(s2.getName()+","+s2.getAge());
}
}
class Persons{
private String name;
private int age;
public Persons() {
System.out.println("父类中的无参构造");
}
public Persons(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Students extends Persons{
public Students(){
//这里默认存在super()调用父类的无参构造方法
System.out.println("子类中的无参构造方法");
}
public Students(String name,int age){
super(name,age);
}
}
最终结果
父类中的无参构造
子类中的无参构造方法
zhangsna,24
4.this和super总结
这一章节里面用得最多的就是this和super关键字了。
this:表示当前方法调用者的地址
super:表示父类的存储空间
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量 访问本类成员变量 | this.成员方法 访问本类的成员方法 | this.构造方法 访问本类的构造方法 |
super | super.成员变量 访问父类的成员变量 | super.成员方法 访问父类的成员方法 | super(…) 访问父类的成员方法 |
this.构造方法 访问本类的构造方法:
public Students(){
//表示调用本类的构造方法,这时虚拟机就不会调用super了
this(null,0,"传智大学");
// System.out.println(1);
}
为什么调用本类的构造方法后,这时的虚拟机就不调用super了?
难道是因为这时子类的初始化已经不需要父类数据初始化了吗?因为this这里子类自己手动初始化了就不需要父类的数据初始化使用了,所以虚拟机就不调用super了。
三、练习
1.带有继承结构的标准Javabean
1.经理
成员变量:工号,姓名,工资,管理奖金成员方法:工作(管理其他人),吃饭(吃米饭)
2.厨师
成员变量:工号,姓名,工资
成员方法:工作(炒菜),吃饭(吃米饭)
package a02StaticDemo3.Employee;
public class Employee {
private String id;
private String name;
private int weges;
public Employee(String id, String name, int weges) {
this.id = id;
this.name = name;
this.weges = weges;
}
public Employee() {
}
/**
* 获取
* @return id
*/
public String getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(String id) {
this.id = id;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return weges
*/
public int getWeges() {
return weges;
}
/**
* 设置
* @param weges
*/
public void setWeges(int weges) {
this.weges = weges;
}
public void work(){
System.out.println("工作");
}
public void eat(){
System.out.println("吃米饭");
}
}
package a02StaticDemo3.Employee;
public class Manger extends Employee{
private String MangerWages;
public Manger() {
}
public Manger(String id, String name, int weges,String MangerWages) {
super(id,name,weges);
this.MangerWages = MangerWages;
}
/**
* 获取
* @return MangerWages
*/
public String getMangerWages() {
return MangerWages;
}
/**
* 设置
* @param MangerWages
*/
public void setMangerWages(String MangerWages) {
this.MangerWages = MangerWages;
}
@Override
public void work(){
System.out.println("管理其他人");
}
}
package a02StaticDemo3.Employee;
public class Chef extends Employee{
public Chef(){
}
public Chef(String id, String name, int weges){
super(id,name,weges);
}
@Override
public void work(){
System.out.println("炒菜");
}
}
package a02StaticDemo3.Employee;
public class Test {
public static void main(String[] args) {
Manger m = new Manger("0001","zhangsna",8000,"2000");
System.out.println(m.getId()+","+m.getName()+","+m.getWeges()+","+m.getMangerWages());
m.work();
m.eat();
System.out.println("------------");
Chef s = new Chef("0002","lisi",7000);
System.out.println(s.getId()+","+s.getName()+","+s.getWeges());
s.work();
s.eat();
}
}
2.带有继承结构的标准Javabean
在有很多员工(Employee)。
按照工作内容不同分教研部员工(Teacher)和行政部员工(AdminStaff)1.教研部根据教学的方式不同又分为讲师(Lecturer)和助教(Tutor)
2.行政部根据负责事项不同,又分为维护专员(Maintainer),采购专员(Buyer)3.公司的每一个员工都编号,姓名和其负责的工作
4.每个员工都有工作的功能,但是具体的工作内容又不一样。
分析:画图分析
![](https://img-blog.csdnimg.cn/direct/49f1fce7de634e37908b146bb5239ad3.png)
package a02StaticDemo3.employee2;
public class Employee {
private String id;
private String name;
public Employee(){
}
public Employee(String id,String name){
this.id = id;
this.name = name;
}
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
public void work(){
System.out.println("在工作");
}
}
package a02StaticDemo3.employee2;
public class Teacher extends Employee{
public Teacher(){
}
public Teacher(String id,String name){
super(id,name);
}
@Override
public void work(){
System.out.println("干教研工作");
}
}
package a02StaticDemo3.employee2;
public class Lectear extends Teacher{
public Lectear(){
}
public Lectear(String id,String name){
super(id,name);
}
@Override
public void work(){
System.out.println("讲师工作");
}
}
package a02StaticDemo3.employee2;
public class Tutor extends Teacher{
public Tutor(){
}
public Tutor(String id,String name){
super(id,name);
}
@Override
public void work(){
System.out.println("干助教工作");
}
}
package a02StaticDemo3.employee2;
public class AdminStaff extends Employee{
public AdminStaff(){
}
public AdminStaff(String id,String name){
super(id,name);
}
@Override
public void work(){
System.out.println("干行政工作");
}
}
package a02StaticDemo3.employee2;
public class Maintainer extends AdminStaff{
public Maintainer(){
}
public Maintainer(String id,String name){
super(id,name);
}
@Override
public void work(){
System.out.println("干维护工作");
}
}
package a02StaticDemo3.employee2;
public class Buger extends AdminStaff{
public Buger(){
}
public Buger(String id,String name){
super(id,name);
}
@Override
public void work(){
System.out.println("干采购工作");
}
}
总结
- 继承是当属于同一种类具有公共代码的则可以提取出来,然后继承再添加上不同的代码。
- 方法重写是父类的代码不能满足子类的需求时则需要重写,格式与父类最后完全一致(子类修饰符要大于父类修饰符,子类返回值要小于父类返回值,),然后方法重写前面加上@override检察格式
- 只有虚方法表中的方法才可以被继承,即static,private,final不可以
- 成员方法和变量的特点:就近原则,构造方法的特点则是不能被继承使用
- super可以调用父类的方法和构造方法,成员变量