Java 继承 父类、子类、继承的本质

继承可以解决代码复用,让编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。

  • 父类又叫超类、基类
  • 子类又叫派生类

继承的基本语法:

class 子类类名 extends 父类类名{
}

**继承的示意图:**​​

image

快速入门

定义一个父类

package object02.extend_;

/**
 * 父类,是Pupil和Graduate的父类
 */
public class Student {

    // 三个共有的属性
    public String name;
    public int age;
    private double score;   // 成绩


    // 两个共有的方法
    public void setScore(double score) {
        this.score = score;
    }

    public void showInfo() {
        System.out.println("学生名:" + name);
        System.out.println("年龄:" + age);
        System.out.println("成绩:" + score);
    }

}

定义两个子类

package object02.extend_;

/**
 * 继承学生类
 */
public class Pupil extends Student{

    // 只要写不一样的方法就可以
    public void testing() {
        System.out.println("小学生" + name + "正在考小学数学...");
    }

}
package object02.extend_;

/**
 * 继承学生类
 */
public class Graduate extends Student{

    // 只要写不一样的方法就可以
    public void testing() {
        System.out.println("大学生" + name + "正在考大学数学...");
    }

}

测试方法

package object02.extend_;

public class Test {
    public static void main(String[] args) {
        Graduate graduate = new Graduate();
        graduate.name = "张大三";
        graduate.age = 20;
        graduate.testing();
        graduate.setScore(89);
        graduate.showInfo();

        Pupil pupil = new Pupil();
        pupil.name = "张小三";
        pupil.age = 9;
        pupil.testing();
        pupil.setScore(67);
        pupil.showInfo();
    }
}

输出结果

image

继承详解

  1. 子类继承了所有父类的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,需要通过公共方法去访问。
  2. 子类必须调用父类的构造器,完成父类的初始化
  3. 当使用super调用父类构造器时,必须将super()语句放在子类构造器的第一行。
  4. 如果希望指定调用父类的某个构造器,可以手动的显式调用
  5. this()和super()都只能放在构造器的第一行,所以在同一个构造器中不能同时出现这两个方法
  6. 在Java中,所有类都是Object的子类,Object类是所有类的父类(默认继承,所以没有extends关键字)
  7. 当子类创建对象时,父类的构造器的调用不限于直接父类,将一直追溯到Object类 (图)
  8. Java是单继承机制。一个子类最多直接继承一个父类
  9. 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

定义一个父类,父类中分别有四个权限修饰符所修饰的属性和方法,还有一个无参的构造器

public class Base {
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;
    public Base() {
        System.out.println("Base的无参构造执行了");
    }
    public void test01() {
        System.out.println("test01执行了");
    }
    protected void test02() {
        System.out.println("test02执行了");
    }
    void test03() {
        System.out.println("test03执行了");
    }
    private void test04() {
        System.out.println("test04执行了");
    }
}

定义一个子类,有一个无参的构造器

public class Sub extends Base {
    public Sub() {
        System.out.println("Sub的无参构造执行了");
    }

    public void sayOk(){
    }
}

测试方法

public class Test {
    public static void main(String[] args) {
        Sub sub = new Sub();
    }
}

子类继承了所有父类的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,需要通过公共方法去访问。

哪怕当父类和子类在同一个包中的时候,子类访问不到父类的私有属性和私有方法。

image

image

如果想调用,可以父类提供间接访问的方法,比如setget方法,或者其他方法折中调用等等,下面的代码加入到父类中可以间接的访问私有的属性和方法(我不能做的事情,可以叫别人帮忙做)。

    public int getN4() {
        return n4;
    }
    public void getTest04() {
        test04();
    }

而通过debug工具,可以发现私有属性n4被被子类Sub继承了,所以子类继承了所有父类的属性和方法,包括私有的属性和方法。

image

子类必须调用父类的构造器,完成父类的初始化

执行测试方法,可以看到以下结果

image

这里相当于是在子类的构造器中的第一行使用了super关键字,如果父类有无参构造器,super()可以省略不写,系统会自动调用。

image

创建子类对象的时候不管使用的是子类的哪个构造器(无参或者有参构造),默认情况下都会调用父类的无参构造器如果父类没有无参构造器,则必须在子类的构造器的第一行使用super(参数列表)去调用父类的构造器,否则编译不通过
此时给父类和子类都加上一个有参构造器,如下

image

image

再次运行测试方法,可以证实:在默认的情况下,不管子类调用哪个构造器,父类都会调用无参构造

image

把父类的无参构造器注释,只保留有参构造

image

这时可以看到,子类的两个构造器直接报错

image

并且必须把super()语句写在子类构造器的第一行

当使用super调用父类构造器时,必须将super()语句放在子类构造器的第一行。

image

image

此时执行测试方法,可以看到调用的是父类的有参构造器

image

如果希望指定调用父类的某个构造器,可以手动的显式调用

现在将父类构造器恢复成一个有参构造和一个无参构造,此时的子类是可以使用super关键字手动调用父类的任何一个构造器,当然,如果不手动调用,则会默认调用无参构造。

现在的代码是子类无参构造器调用父类的有参构造器,子类的有参构造器调用父类的无参构造器

image

可以看到输出结果

image

this()和super()都只能放在构造器的第一行,所以在同一个构造器中不能同时出现这两个方法

可以看到,当同时调用的时候,直接报错

image

在Java中,所有类都是Object的子类,Object类是所有类的父类(默认继承,所以没有extends关键字)

在idea中,使用快捷键Ctrl + H快捷键可以调出类的继承关系,可以看到,定义的Sub类的父类是Base类,而Base类又是Object类的子类,所以,Sub类也是Object类的子类。

image

当子类创建对象时,父类的构造器的调用不限于直接父类,将一直追溯到Object类

image

创建这三个类,每个类中都有一个无参构造,无参构造会输出一句话,关系图如下

image

image

可以看到,当创建C类对象的时候,构造器会从顶级父类开始执行,因为Object类的构造器没有输出(实际上A类的构造器中也隐藏了super()语句,也会去调用Object类的无参构造器),所以从A类开始输出,一直输出到C类结束

image

Java是单继承机制。一个子类最多直接继承一个父类

不可以多继承

image

image

如果C类既想继承A类又想继承B类,可以让A类继承B类,然后C类继承A类,或者B类继承A类,再C类继承B类

不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

比如Cat类(猫)继承Animal类(动物)是合理的,因为猫有动物的特征,Animal类可以从Cat类或者Dog类中抽取出共同的方法或属性。

但是Person类(人)继承Music类(音乐),没有共同特征,不合适继承。

继承的本质

如图,从右往左看

image

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VincentHu_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值