页首Html代码

08-Java继承

8.1 为什么需要继承

看一个案例
创建了一个小学生的类

创建了一个大学生的类

最后调用了这两个类

Pupil和graduate这两个类的属性和方法都是一摸一样,如果按照上面这样子写代码就会冗余,麻烦,这个时候就可以使用继承来解决这个问题。

8.2 继承的介绍

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

  1. 如上图所示,B类和C类的属性有很多的相同的属性和方法
  2. 再写一个A类,把B类和C类共有的属性和方法写在A类里面
  3. 通过关键字extends让B类和C类都继承A类的属性和方法,A类就是父类,B类和C类继承了A类的属性和方法,叫字类。
  4. D类和E类也可以i继承B类和C类的属性和方法,同时也可以继承A类的属性和方法,关系类似于:孙子--爸爸--爷爷。

8.3 继承入门案例

对上面提到案例的改进

  1. 新建一个父类Student,把子类Pupil和子类Grauate共有的属性和方法写在父类里面。
  2. 再在Pupil和Graduate子类里写子类特有的属性和方法,然后继承父类。

  3. 最后直接调用Student父类里面的方法和属性就可以了

    继承的好处
  4. 代码的复用性提高了
  5. 代码的扩展性和维护性提高了,以后我如果需要加共有属性和方法的话,直接在父类Student写就行。

8.4 继承使用细节

  1. 子类继承了所有的属性和方法,但是私有属性不能在子类直接访问,需要通过公共的方法去访问。
    父类
package com.edu.extens_;

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的方法,返回了N4
    public int getN4() {
        return n4;
    }
    public void test100() {
        System.out.println("test100");
    }
    protected void test200() {
        System.out.println("test200");
    }
    void test300() {
        System.out.println("test300");
    }
    private void test400() {
        System.out.println("test400");
    }
}

Sub子类

package com.edu.extens_;
//子类
public class Sub extends Base {//子类
    public void sayok() {
        //非私有的属性和方法可以在子类直接访问
        //但是私有属性和方法不能在子类直接访问
        System.out.println(n1 + " " + n2 + " " + n3);
        test100();
        test200();
        test300();
        //test400();错误,私有属性和方法不能直接访问
        //需要通过父类提供的公共方法来访问
        System.out.println("n4=" + getN4());

    }
}

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


3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下都会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类构造器中用super();去指定使用父类的哪个构造器完成对父类的初始化工作,否则会编译不通过。
4. 如果希望指定去调用父类的某个构造器,则显示调用以下
5. super在使用时,需要放在构造器的第一行。
6. super()和this()都是只能放在构造器第一行,因此这两个方法不能共存在一个构造器,只能使用其中的一个。
7. Java所有类都是Object类的子类,Object是所有类的基类。
8. 父类构造器的调用不限于直接父类,将一直网上追溯直到Object类。

8.5 继承的本质分析

看一个案例,GranPa类是Father类的父类,Father类是son的父类,是这种继承关系。

当执行son son = new son();后会在内存里面发生什么事情呢?

  1. new son();的时候会加载类信息,首先加载GranPa类信息,然后再加载Father类信息,最后再加载son类信息。因为他们是继承关系,son--继承了Father类,Father--继承了GranPa类,GranPa继承了--Object。
  2. 加载完类信息后,GranPa类开始堆里面开空间,name,hoby是字符串,放在常量池里。
  3. Father类也堆里面开空间,name放在常量池里,age变量放在堆里面。
  4. son类也是在堆里面开空间,那么放在常量池。
    5.当堆里面的空间和数据分配好之后,堆里面的地址把它返回给主方法的son对象。
    返回信息的时候要按照查找关系来返回信息:
  5. 首先看子类是有该属性。
  6. 如果子类有这个属性,并且可以访问,则返回信息。
  7. 如果子类没有这个熟悉那个,就看父类有没有这个属性(如果父类有,并且可以访问,就返回信息)。
  8. 如果父类没有,就按照第3条规则,继续找上级父类,直到Object,如果还没有就报错。

8.6 继承练习题

父类

package com.edu.extens_.exercise;

public class PC extends Computer{
    private String brand;

    public PC(String cpu, int memory, int disk, String brand) {
        super(cpu, memory, disk);
        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
    public void printInfo() {
        System.out.println(getDetals() + " brand=" + brand);
    }
}

子类

package com.edu.extens_.exercise;

public class PC extends Computer{
    private String brand;

    public PC(String cpu, int memory, int disk, String brand) {
        super(cpu, memory, disk);
        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
    public void printInfo() {
        System.out.println(getDetals() + " brand=" + brand);
    }
}

打印输出

package com.edu.extens_.exercise;
/*
* 编写Computer类,包含CPU、内存、
* 硬盘等属性,getDetails方法用于
* 返回Computer的详细信息
* 编写PC子类,继承Computer类,添加特有属性品牌brand
* 在ExtendsExercise类main方法中创建PC对象,分别给
* 对象中特有的属性赋值,以及从Computer类继承的属性赋值,并使用方法打印输出信息。
* */
public class ExtendsExercise {
    public static void main(String[] args) {
        PC pc = new PC("intel",16,500,"ibm");
        pc.printInfo();
    }
}
posted @ 2022-03-30 23:36  与或非丶  阅读(49)  评论(0)    收藏  举报