【从零开始学Java笔记】继承

大家可以关注作者的账号,关注从零开始学Java笔记文集。也可以根据目录前往作者的博客园博客进行学习。本片文件将基于黑马程序员就业班视频进行学习以及资料的分享,并记录笔记和自己的看法。欢迎大家一起学习和讨论。

【从零开始学Java笔记】目录

什么是继承?

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

简单的说就是多个类有相同的成员变里和成员方法,为了避免代码的重复,可以先写一个父类,包含共同的属性,然后再由子类继承。

关键字:extends

下面举个例子:

  1. 不使用继承
class GuanYu{
    String name;
    int age;
    String address;
    
    public void win() {
        System.out.println("关羽赢了!");
    }
    
    public void lose() {
        System.out.println("关羽输了!");
    }
}

class LvBu{
    String name;
    int age;
    String address;
    
    public void win() {
        System.out.println("吕布赢了!");
    }
    
    public void lose() {
        System.out.println("吕布输了!");
    }
}

可以看出无论是关羽还是吕布都拥有成员变量:姓名,年龄和地址成员方法:赢和输。如果想写一百个武将,十分繁琐。所以使用继承,写一个父类,先寻找他们的共性,那就是他们都是人,所以写一个people类,包含他们共同的属性和方法。如下:

class Person{
    
    String name;
    int age;
    String address;
    
    public void win() {
        System.out.println("关羽赢了!");
    }
    
    public void lose() {
        System.out.println("关羽输了!");
    }
}
class GuanYu extends Person{
    
}

class LvBu extends Person{
    
}

Java中维承的特点

  • Java语言只支持单一继承,只能继承一个父类(一个儿子只能有一个亲爹)
    Java语言支持多层继承(一个儿子可以有一个亲爹, 还可以有一个亲爷爷)

继承中成员变量的特点

  • 子类只能获取父类非私有成员
    子父类中成员变量的名字不一样 直接获取父类的成员变里
    子父类中成员变量名字是一样的获取的是子类的成员变量
class GuanYu{
    private String wifeName = "null";
    String name = "GuanYu";
    
}

class GuanXing extends GuanYu{
    String name = "GuanXing";//如果没有这句,show()输出GuanYu
    
    public void show() {
//      System.out.println(wifename); 子类无法继承父类的私有变量,报错
        System.out.println(name);//输出GuanXing
    }

给大家出一道题,大家思考一下三个输出语句的结果,如果能理解基本上就没什么问题了
这里为大家补充一个就近原则:谁离我近我就用谁
如果有局部变量就使用局部变量
如果没有局部变量,有子类的成员变量就使用子类的成员变量
如果没有局部变量和子类的成员变量,有父类的成员变量就使用父类的成员变量
啥都没有,出错了! ! !|

class GuanYu{
    
    String name = "关羽";
    
}

class GuanXing extends GuanYu{
    String name = "关兴";
    public void show() {
        String name = "关平";
        
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
}

super :可以获取父类的成员变量和成员方法
this:可以获取当前类的成员变量和成员方法

输出结果
关平
关兴
关羽

继承中成员方法的特点

和成员变量相似

  • 子类中没有这个方法,调用父类的
    子类中重写了这个方法,调用子类的

重写和重载的区别
方法的重写:在子父类当中,子类的方法和父类的完全一样,子类重写了父类的方法(覆盖),当子类重写了父类的方法之后,使用子类对象调用的就是子类的方法
方法的重载:在一个类中,有多个重名的方法,但是其参数不一样(参数的个数,参数的类型,参数的顺序),和返回值无关

方法重写的应用场景

  • 当父类的方法不能完全满足子类使用,这个时候子类重写父类的方法
    并可以在方法中使用关键字super调用父类的方法,这样做即可以保有父类的功能,也可以拥有子类持有的功能

这里给大家举个例子

class GuanYu{
    public void attack() {
        System.out.println("拖刀");
    }
}

class GuanXing extends GuanYu{
    public void attack() {
        super.attack();
        System.out.println("斩");
    }

其实很简单,关兴继承了父亲的攻击方式,但是在拖刀的前提下加入了斩,使威力更强。这里为什么使用super.attack()为什么不直接复制过来,这里可以想象拖刀是一个很复杂的过程,但是我们这里简写,如果关羽攻击的函数有1000行代码,调用比复制更方便,也更好看。

方法重写的注意事项

不能重写父类私有的方法
权限必须大于等于父类方法的权限(了解即可)

注解: @ 一般写在方法、变量、类前面,用来描述方法、变量、类,目的是提高代码规范

还用刚才那个例子

class GuanYu{
    public void attack() {
        System.out.println("拖刀");
    }
}

class GuanXing extends GuanYu{
//  public void attck() {
//      super.attack();
//      System.out.println("斩");
//  }
    public void attack(String a) {
        super.attack();
        System.out.println("斩");
    }

如果我们给子类的方法加一个形参 string a ,或者错写成attck()并不会报错,但是这个已经不算是方法的重写了

这时候我们在重写的代码前加上@Override,就会报错。

继承中构造方法的执行顺序

public class ExtendsDemo2 {
    public static void main(String[] args) {
        GuanYu gy = new GuanYu();
        System.out.println("****************");
        GuanXing gx = new GuanXing();
        
    }
    

}

class GuanYu{

    public GuanYu() {
        System.out.println("这是关羽的无参构造");
    }
    public GuanYu(int a) {
        System.out.println("这是关羽的有参构造");
    }
    
}

class GuanXing extends GuanYu{
    public GuanXing() {
        System.out.println("这是关兴的无参构造");
    }
    public GuanXing(int a) {
        System.out.println("这是关兴的有参构造");
    }
    
}

输出结果

这是关羽的无参构造
****************
这是关羽的无参构造
这是关兴的无参构造

为什么调用子类的无参构造的时候,也会调用父类的无参构造?
在有子父类继承关系的类中,创建子类的对象,调用子类的构造方法,如果子类构造方法的第一行代码没有调用父类的构造方法,则会默认的调用父类的无参构造

我们可以使用super( )在子类构造方法的第一行中调用父类的构造方法

class GuanXing extends GuanYu{
    public GuanXing() {
        //super(1);  //测试1
        //this(2); //测试2
        System.out.println("这是关兴的无参构造");
    }
    public GuanXing(int a) {
        System.out.println("这是关兴的有参构造");
    }

可以分别取消测试1和测试2的注释,再运行,看看结果。

为什么会有这个设定呢?因为必须先执行父类的构造,要先给父类的成员变里进行初始化,子类可能会使用到。

this和super的区别

this:当前对象的引用
调用子类的成员变量
调用子类的成员方法
在子类的构造方法第一行调用子类其他构造方法
super:子类对象的父类引用
调用父类的成员变量
调用父类的成员方法
在子类的构造方法第一行调用父类的构造方法

继承的优缺点

优点

  • 提高了代码的复用性
  • 提高了代码的可维护性

缺点

  • 类的耦合性增强了
  • 开发的原则:高内聚低耦合
  • 内聚:就是自己完成某件事情的能力
  • 耦合:类与类的关系

通俗易懂的来说就是继承可以只通过修改父类的属性来实现子类属性的同步修改,这样会很方便。例如,奥迪,宝马都是汽车的子类,如果想让所有品牌汽车的价格增加15%,只需要再父类里面进行操作即可。但是同时也会出现问题,父类的属性进行修改,子类的属性必定进行修改,但有时或出现错误。例如删掉增加15%的价格,所有的品牌都会自动删除,如果有一些其他和价格有关的方法就会出现错误。其实这样就是高耦合的表现,类与类之间关系十分紧密,牵一发而动全身。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容