1 概述

1.1 引入

如果咱们要定义如下类:
学生类,老师类和工人类,剖析如下。

  1. 学生类
    属性:姓名,年龄
    行为:吃饭,睡觉
  2. 老师类
    属性:姓名,年龄,薪水
    行为:吃饭,睡觉,教书
  3. 班主任
    属性:姓名,年龄,薪水
    行为:吃饭,睡觉,治理

如果咱们定义了这三个类去开发一个零碎,那么这三个类中就存在大量反复的信息(属性:姓名,年龄。行为:吃饭,睡觉)。这样就导致了雷同代码大量反复,代码显得很臃肿和冗余,那么如何解决呢?

如果多个类中存在雷同属性和行为时,咱们能够将这些内容抽取到独自一个类中,那么多个类无需再定义这些属性和行为,只有继承那一个类即可。如图所示:

其中,多个类能够称为子类,独自被继承的那一个类称为父类超类(superclass)或者基类

1.2 继承的含意

继承形容的是事物之间的所属关系,这种关系是:is-a 的关系。例如,兔子属于食草动物,食草动物属于动物。可见,父类更通用,子类更具体。咱们通过继承,能够使多种事物之间造成一种关系体系。

继承:就是子类继承父类的属性行为,使得子类对象能够间接具备与父类雷同的属性、雷同的行为。子类能够间接拜访父类中的非公有的属性和行为。

1.3 继承的益处

  1. 进步代码的复用性(缩小代码冗余,雷同代码反复利用)。
  2. 使类与类之间产生了关系。

2 继承的格局

通过 extends 关键字,能够申明一个子类继承另外一个父类,定义格局如下:

class 父类 {    ...}class 子类 extends 父类 {    ...}

须要留神:Java是单继承的,一个类只能继承一个间接父类,跟事实世界很像,然而Java中的子类是更加弱小的。

3 继承案例

3.1 案例

请应用继承定义以下类:

  1. 学生类
    属性:姓名,年龄
    行为:吃饭,睡觉
  2. 老师类
    属性:姓名,年龄,薪水
    行为:吃饭,睡觉,教书
  3. 班主任
    属性:姓名,年龄,薪水
    行为:吃饭,睡觉,治理

3.2 案例图解剖析

老师类,学生类,还有班主任类,实际上都是属于人类的,咱们能够定义一个人类,把他们雷同的属性和行为都定义在人类中,而后继承人类即可,子类特有的属性和行为就定义在子类中了。

如下图所示。

3.3 案例代码实现

1.父类Human类

 public class Human {  // 正当暗藏  private String name ;  private int 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;  } }

2.子类Teacher类

public class Teacher extends Human {  // 工资  private double salary ;    // 特有办法  public void teach(){      System.out.println("老师在认真教技术!");  }  public double getSalary() {      return salary;  }  public void setSalary(double salary) {      this.salary = salary;  }}

3.子类Student类

public class Student extends Human{ }

4.子类BanZhuren类

public class Teacher extends Human {    // 工资    private double salary ;           // 特有办法    public void admin(){        System.out.println("班主任强调纪律问题!");    }        public double getSalary() {        return salary;    }    public void setSalary(double salary) {        this.salary = salary;    }}

5.测试类

public class Test {    public static void main(String[] args) {        Teacher dlei = new Teacher();        dlei.setName("播仔");        dlei.setAge("31");        dlei.setSalary(1000.99);        System.out.println(dlei.getName());        System.out.println(dlei.getAge());        System.out.println(dlei.getSalary());        dlei.teach();                BanZhuRen linTao = new BanZhuRen();        linTao.setName("灵涛");        linTao.setAge("28");        linTao.setSalary(1000.99);        System.out.println(linTao.getName());        System.out.println(linTao.getAge());        System.out.println(linTao.getSalary());        linTao.admin();        Student xugan = new Student();        xugan.setName("播仔");        xugan.setAge("31");        //xugan.setSalary(1000.99); // xugan没有薪水属性,报错!        System.out.println(xugan.getName());        System.out.println(xugan.getAge());    }}

3.4 小结

1.继承实际上是子类雷同的属性和行为能够定义在父类中,子类特有的属性和行为由本人定义,这样就实现了雷同属性和行为的反复利用,从而进步了代码复用。

2.子类继承父类,就能够间接失去父类的成员变量和办法。是否能够继承所有成分呢?请看下节!

4 子类不能继承的内容

4.1 引入

并不是父类的所有内容都能够给子类继承的:

子类不能继承父类的构造方法。

值得注意的是子类能够继承父类的公有成员(成员变量,办法),只是子类无奈间接拜访而已,能够通过getter/setter办法拜访父类的private成员变量。

4.1 演示代码

public class Demo03 {    public static void main(String[] args) {        Zi z = new Zi();        System.out.println(z.num1);//        System.out.println(z.num2); // 公有的子类无奈应用        // 通过getter/setter办法拜访父类的private成员变量        System.out.println(z.getNum2());        z.show1();        // z.show2(); // 公有的子类无奈应用    }}class Fu {    public int num1 = 10;    private int num2 = 20;    public void show1() {        System.out.println("show1");    }    private void show2() {        System.out.println("show2");    }    public int getNum2() {        return num2;    }    public void setNum2(int num2) {        this.num2 = num2;    }}class Zi extends Fu {}

5 继承后的特点—成员变量

当类之间产生了继承关系后,其中各类中的成员变量,又产生了哪些影响呢?

5.1 成员变量不重名

如果子类父类中呈现不重名的成员变量,这时的拜访是没有影响的。代码如下:

class Fu {    // Fu中的成员变量    int num = 5;}class Zi extends Fu {    // Zi中的成员变量    int num2 = 6;      // Zi中的成员办法    public void show() {        // 拜访父类中的num        System.out.println("Fu num="+num); // 继承而来,所以间接拜访。        // 拜访子类中的num2        System.out.println("Zi num2="+num2);    }}class Demo04 {    public static void main(String[] args) {        // 创立子类对象        Zi z = new Zi();           // 调用子类中的show办法        z.show();      }}演示后果:Fu num = 5Zi num2 = 6

5.2 成员变量重名

如果子类父类中呈现重名的成员变量,这时的拜访是有影响的。代码如下:

class Fu1 {    // Fu中的成员变量。    int num = 5;}class Zi1 extends Fu1 {    // Zi中的成员变量    int num = 6;      public void show() {        // 拜访父类中的num        System.out.println("Fu num=" + num);        // 拜访子类中的num        System.out.println("Zi num=" + num);    }}class Demo04 {    public static void main(String[] args) {          // 创立子类对象        Zi1 z = new Zi1();           // 调用子类中的show办法        z1.show();     }}演示后果:Fu num = 6Zi num = 6

子父类中呈现了同名的成员变量时,子类会优先拜访本人对象中的成员变量。如果此时想拜访父类成员变量如何解决呢?咱们能够应用super关键字。

5.3 super拜访父类成员变量

子父类中呈现了同名的成员变量时,在子类中须要拜访父类中非公有成员变量时,须要应用super 关键字,润饰父类成员变量,相似于之前学过的 this

须要留神的是:super代表的是父类对象的援用,this代表的是以后对象的援用。

应用格局:

super.父类成员变量名

子类办法须要批改,代码如下:

class Fu {    // Fu中的成员变量。    int num = 5;}class Zi extends Fu {    // Zi中的成员变量    int num = 6;      public void show() {        int num = 1;              // 拜访办法中的num        System.out.println("method num=" + num);        // 拜访子类中的num        System.out.println("Zi num=" + this.num);        // 拜访父类中的num        System.out.println("Fu num=" + super.num);    }}class Demo04 {    public static void main(String[] args) {          // 创立子类对象        Zi1 z = new Zi1();           // 调用子类中的show办法        z1.show();     }}演示后果:method num=1Zi num=6Fu num=5
小贴士:Fu 类中的成员变量是非公有的,子类中能够间接拜访。若Fu 类中的成员变量公有了,子类是不能间接拜访的。通常编码时,咱们遵循封装的准则,应用private润饰成员变量,那么如何拜访父类的公有成员变量呢?对!能够在父类中提供公共的getXxx办法和setXxx办法。

6 继承后的特点—成员办法

当类之间产生了关系,其中各类中的成员办法,又产生了哪些影响呢?

6.1 成员办法不重名

如果子类父类中呈现不重名的成员办法,这时的调用是没有影响的。对象调用办法时,会先在子类中查找有没有对应的办法,若子类中存在就会执行子类中的办法,若子类中不存在就会执行父类中相应的办法。代码如下:

class Fu {    public void show() {        System.out.println("Fu类中的show办法执行");    }}class Zi extends Fu {    public void show2() {        System.out.println("Zi类中的show2办法执行");    }}public  class Demo05 {    public static void main(String[] args) {        Zi z = new Zi();         //子类中没有show办法,然而能够找到父类办法去执行        z.show();         z.show2();    }}

6.2 成员办法重名

如果子类父类中呈现重名的成员办法,则创立子类对象调用该办法的时候,子类对象会优先调用本人的办法。

代码如下:

class Fu {    public void show() {        System.out.println("Fu show");    }}class Zi extends Fu {    //子类重写了父类的show办法    public void show() {        System.out.println("Zi show");    }}public class ExtendsDemo05{    public static void main(String[] args) {        Zi z = new Zi();         // 子类中有show办法,只执行重写后的show办法        z.show();  // Zi show    }}

7 办法重写

7.1 概念

办法重写 :子类中呈现与父类截然不同的办法时(返回值类型,办法名和参数列表都雷同),会呈现笼罩成果,也称为重写或者复写。申明不变,从新实现

7.2 应用场景与案例

产生在子父类之间的关系。
子类继承了父类的办法,然而子类感觉父类的这办法不足以满足本人的需要,子类从新写了一个与父类同名的办法,以便笼罩父类的该方 法。

例如:咱们定义了一个动物类代码如下:

public class Animal  {    public void run(){        System.out.println("动物跑的很快!");    }    public void cry(){        System.out.println("动物都能够叫~~~");    }}

而后定义一个猫类,猫可能认为父类cry()办法不能满足本人的需要

代码如下:

public class Cat extends Animal {    public void cry(){        System.out.println("咱们一起学猫叫,喵喵喵!喵的十分好听!");    }}public class Test {    public static void main(String[] args) {          // 创立子类对象          Cat ddm = new Cat();        // 调用父类继承而来的办法        ddm.run();          // 调用子类重写的办法          ddm.cry();    }}

7.2 @Override重写注解

  • @Override:注解,重写注解校验!
  • 这个注解标记的办法,就阐明这个办法必须是重写父类的办法,否则编译阶段报错。
  • 倡议重写都加上这个注解,一方面能够进步代码的可读性,一方面能够避免重写出错!

    加上后的子类代码模式如下:

    public class Cat extends Animal {     // 申明不变,从新实现    // 办法名称与父类全副一样,只是办法体中的性能重写写了!    @Override    public void cry(){        System.out.println("咱们一起学猫叫,喵喵喵!喵的十分好听!");    }}

7.3 注意事项

  1. 办法重写是产生在子父类之间的关系。
  2. 子类办法笼罩父类办法,必须要保障权限大于等于父类权限。
  3. 子类办法笼罩父类办法,返回值类型、函数名和参数列表都要截然不同。

8 继承后的特点—构造方法

8.1 引入

当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?
首先咱们要回顾两个事件,构造方法的定义格局和作用。

  1. 构造方法的名字是与类名统一的。所以子类是无奈继承父类构造方法的。
  2. 构造方法的作用是初始化对象成员变量数据的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,示意调用父类的构造方法,父类成员变量初始化后,才能够给子类应用。(先有爸爸,能力有儿子

继承后子类构办法器特点:子类所有构造方法的第一行都会默认先调用父类的无参构造方法

8.2 案例演示

按如下需要定义类:

  1. 人类
    成员变量: 姓名,年龄
    成员办法: 吃饭
  2. 学生类
    成员变量: 姓名,年龄,问题
    成员办法: 吃饭

代码如下:

class Person {    private String name;    private int age;    public Person() {        System.out.println("父类无参");    }    // getter/setter省略}class Student extends Person {    private double score;    public Student() {        //super(); // 调用父类无参,默认就存在,能够不写,必须再第一行        System.out.println("子类无参");    }         public Student(double score) {        //super();  // 调用父类无参,默认就存在,能够不写,必须再第一行        this.score = score;            System.out.println("子类有参");     }}public class Demo07 {    public static void main(String[] args) {        Student s1 = new Student();        System.out.println("----------");        Student s2 = new Student(99.9);    }}输入后果:父类无参子类无参----------父类无参子类有参

8.3 小结

  • 子类构造方法执行的时候,都会在第一行默认先调用父类无参数构造方法一次。
  • 子类构造方法的第一行都隐含了一个super()去调用父类无参数构造方法,super()能够省略不写。

9 super(...)和this(...)

9.1 引入

请看上节中的如下案例:

class Person {    private String name;    private int age;    public Person() {        System.out.println("父类无参");    }    // getter/setter省略}class Student extends Person {    private double score;    public Student() {        //super(); // 调用父类无参构造方法,默认就存在,能够不写,必须再第一行        System.out.println("子类无参");    }         public Student(double score) {        //super();  // 调用父类无参构造方法,默认就存在,能够不写,必须再第一行        this.score = score;            System.out.println("子类有参");     }      // getter/setter省略}public class Demo07 {    public static void main(String[] args) {        // 调用子类有参数构造方法        Student s2 = new Student(99.9);        System.out.println(s2.getScore()); // 99.9        System.out.println(s2.getName()); // 输入 null        System.out.println(s2.getAge()); // 输入 0    }}

咱们发现,子类有参数构造方法只是初始化了本人对象中的成员变量score,而父类中的成员变量name和age仍然是没有数据的,怎么解决这个问题呢,咱们能够借助与super(...)去调用父类构造方法,以便初始化继承自父类对象的name和age.

9.2 super和this的用法格局

super和this残缺的用法如下,其中this,super拜访成员咱们曾经接触过了。

this.成员变量        --    本类的super.成员变量        --    父类的this.成员办法名()      --    本类的    super.成员办法名()   --    父类的

接下来咱们应用调用构造方法格局:

super(...) -- 调用父类的构造方法,依据参数匹配确认this(...) -- 调用本类的其余构造方法,依据参数匹配确认

9.3 super(....)用法演示

代码如下:

class Person {    private String name ="凤姐";    private int age = 20;    public Person() {        System.out.println("父类无参");    }        public Person(String name , int age){        this.name = name ;        this.age = age ;    }    // getter/setter省略}class Student extends Person {    private double score = 100;    public Student() {        //super(); // 调用父类无参构造方法,默认就存在,能够不写,必须再第一行        System.out.println("子类无参");    }         public Student(String name , int age,double score) {        super(name ,age);// 调用父类有参构造方法Person(String name , int age)初始化name和age        this.score = score;            System.out.println("子类有参");     }      // getter/setter省略}public class Demo07 {    public static void main(String[] args) {        // 调用子类有参数构造方法        Student s2 = new Student("张三",20,99);        System.out.println(s2.getScore()); // 99        System.out.println(s2.getName()); // 输入 张三        System.out.println(s2.getAge()); // 输入 20    }}

留神:

子类的每个构造方法中均有默认的super(),调用父类的空参结构。手动调用父类结构会笼罩默认的super()。

super() 和 this() 都必须是在构造方法的第一行,所以不能同时呈现。

super(..)是依据参数去确定调用父类哪个构造方法的。

9.4 super(...)案例图解

父类空间优先于子类对象产生

在每次创立子类对象时,先初始化父类空间,再创立其子类对象自身。目标在于子类对象中蕴含了其对应的父类空间,便能够蕴含其父类的成员,如果父类成员非private润饰,则子类能够随便应用父类成员。代码体现在子类的结构七调用时,肯定先调用父类的构造方法。了解图解如下:

9.5 this(...)用法演示

this(...)

  • 默认是去找本类中的其余构造方法,依据参数来确定具体调用哪一个构造方法。
  • 为了借用其余构造方法的性能。
package com.itheima._08this和super调用构造方法;/** * this(...): *    默认是去找本类中的其余构造方法,依据参数来确定具体调用哪一个构造方法。 *    为了借用其余构造方法的性能。 * */public class ThisDemo01 {    public static void main(String[] args) {        Student xuGan = new Student();        System.out.println(xuGan.getName()); // 输入:徐干        System.out.println(xuGan.getAge());// 输入:21        System.out.println(xuGan.getSex());// 输入: 男    }}class Student{    private String name ;    private int age ;    private char sex ;    public Student() {  // 很弱,我的兄弟很牛逼啊,我能够调用其余构造方法:Student(String name, int age, char sex)        this("徐干",21,'男');    }    public Student(String name, int age, char sex) {        this.name = name ;        this.age = age   ;        this.sex = sex   ;    }    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;    }    public char getSex() {        return sex;    }    public void setSex(char sex) {        this.sex = sex;    }}

9.6 小结

  • 子类的每个构造方法中均有默认的super(),调用父类的空参结构。手动调用父类结构会笼罩默认的super()。
  • super() 和 this() 都必须是在构造方法的第一行,所以不能同时呈现。
  • super(..)和this(...)是依据参数去确定调用父类哪个构造方法的。
  • super(..)能够调用父类构造方法初始化继承自父类的成员变量的数据。
  • this(..)能够调用本类中的其余构造方法。

10 继承的特点

  1. Java只反对单继承,不反对多继承。

    // 一个类只能有一个父类,不能够有多个父类。class A {}class B {}class C1 extends A {} // ok// class C2 extends A, B {} // error
  2. 一个类能够有多个子类。

    // A能够有多个子类class A {}class C1 extends A {}class C2 extends  A {}
  3. 能够多层继承。

    class A {}class C1 extends A {}class D extends C1 {}
    顶层父类是Object类。所有的类默认继承Object,作为父类。