【Java学习笔记】27 - 继承

项目代码

https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter08/src/com/yinhai/extend_

        如果编写两个类,两个类的属性很多都相同,只在个别方法不同,会出现代码复用性很差,所以引入继承

目录

项目代码

一、继承的基本介绍

二、继承的基本语法

三、继承的快速入门

四、继承的细节

1.

 2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

五、继承的本质

六、继承的课堂练习

1.

2.

3.


一、继承的基本介绍

        继承可以解决代码复用,当多个类存在相同属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。

        示意图

                

二、继承的基本语法

        class 子类 extends 父类{

        }

1.子类会自动拥有父类定义的属性和方法

2.父类又叫基类,超类

3.子类又叫派生类

三、继承的快速入门

        

public class Graduate extends Student{ // extends表示继承Student父类
    public void testing(){
        System.out.println(name);
    }
}
package com.hspedu.extend_.improve_;
//是Pupli 和 Graduate
public class Student {
    public String name;
    public int age;
    private double score;
    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }
    public void info(){
        System.out.println();
    }
}

四、继承的细节

1.

        子类继承了所有属性和方法,但是私有属性和方法不能再子类直接访问,要通过父类提供的公共的方法去访问

    public String name;
    int age;
    protected int salary;
    private int num;

    public int getNum() {
        return num;
    }

 

 2.

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

public class Base {
    public String name;
    int age;
    protected int salary;
    private int num;
    public Base(){
        System.out.println("父类base...");
    }
}
public class A extends Base{
    public A() {
        //其实这里默认有一句话,写不写都会默认放在这个位置
        //super();//默认调用父类的无参构造器 
        System.out.println("子类A...");
    }
}

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

3.

        当创建子类对象,不管使用子类的哪个构造器,默认情况总会去调用父类的无参构造器。

public class Test {
    public static void main(String[] args) {
        A a = new A();
        A a1 = new A(1);
    }
}

                

如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译将无法通过

public class Test {
    public static void main(String[] args) {
        A a = new A();
        A a1 = new A(1);
    }
}
public class Base {
    public Base(int num){
        System.out.println("父类的num形参构造器base...");
    }
public class A extends Base{
    public A() {
        super(1);
        System.out.println("子类A的无参构造器...");
    }
    public A(int num) {
        super(2);
        System.out.println("子类A的num形参构造器...");
    }

                

4.

        如果希望去调用父类的某个构造器,需要显式的定义一下 super(形式参数);

5.

        super在使用时,必须放在构造器的第一行(super只能在构造器中使用)

6.

        super()和this()都只能放在构造器中使用,所以这两个不能放在一个构造器内使用

7.

        java所有类都是object类的子类,Object是所有类的基类/父类

使用Ctrl + H

                

8.

        父类构造器的调用不限于直接父类 将一直往上追溯直到Obeject类(顶级父类)

                

        ​​​​​​​        

        ​​​​​​​        

还会往上找到Object的无参构造器,在JAVA源码内会有

9.

        子类最多只能继承一个父类 即java中是单继承机制

        ​​​​​​​        

那么如何让A类继承B类和C类呢?

        ​​​​​​​        

10.

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

        ​​​​​​​​​​​​​​        

11.

继承设计的基本思想,父类构造器完成父类的初始化,子类的构造器完成子类的初始化

五、继承的本质

        

package com.hspedu.extend_;

import com.hspedu.modifier.B;

public class ExtendsTheory {
    public static void main(String[] args) {
        Base base = new Base();
    }
}
class TopBase{//顶层类
    String name = "顶层"; 
    String hobby = "旅游";
}
class Base extends TopBase{//父类
    String name = "中层";
    int age = 39;
}
class Default extends Base{//子类
    String name = "底层";
}

        

先加载我们的类,随后在方法区里加载属性信息等

随后在堆里开辟空间,从最顶层开始,依次开辟空间指向常量池,最后声明对象

那么重名对象的属性按照什么规则来访问呢

        //要按照查找关系来返回信息
        //1.首先查看子类是否有该属性
        //2.如果子类有该属性而且可以访问,则返回信息
        //3.如果子类没有这个属性,就看父类有没有这个属性(如果有而且可以访问,就返回该信息
        //如果父类没有就重复3依次往上寻找,直到Object
        System.out.println(base.name); //所以这里返回的就是Default里面的

package com.hspedu.extend_;

import com.hspedu.modifier.B;

public class ExtendsTheory {
    public static void main(String[] args) {
        Base base = new Base();
        //要按照查找关系来返回信息
        //1.首先查看子类是否有该属性
        //2.如果子类有该属性而且可以访问,则返回信息
        //3.如果子类没有这个属性,就看父类有没有这个属性(如果有而且可以访问,就返回该信息
        //如果父类没有就重复3依次往上寻找,直到Object
        System.out.println(base.name); //所以这里返回的就是Default里面的
        
    }
}
class TopBase{//顶层类
    String name = "顶层";
    String hobby = "旅游";
}
class Base extends TopBase{//父类
    String name = "中层";
    int age = 39;
}
class Default extends Base{//子类
    String name = "底层";
}

注意,必须要可以访问,如果其中的一个无法访问就会查找路径就会被阻挡,会直接报错

六、继承的课堂练习

1.

                
 

main中 new B()传入的是无参构造器,在classB类执行,但要运行classB先要初始化父类,因为没有super所以默认初始化 A() 所以第一句输出 a

随后构造完毕后,构造B() 该构造器内有this 所以转到B(String name)构造器 注意,此时会执行该构造器内的默认super接着初始化一次父类 ,所以第二句还是a  (每次调用执行一次初始化) 随后才是该构造器本身的输出语句 第二句输出 b name 

随后接着跑完B()内没有跑完的 所以第四句输出b

所以输出如下

        a 

        a        

        b name

        b

 上面是错误的分析,初始化父类是执行了子类的构造器super();才执行初始化的,而不是一建立空间就初始化。所以正确的应该是,执行调用B()后无参构造器执行,但B无参构造器里有this(形参),会执行本类的形参构造器(this和super不能在一个构造器里面)关键字跳转到B(String name)构造器,随后在{}内执行super();初始化父类,执行输出a ,输出完后执行B(String name)构造器内的b name 输出,最后执行B()的b输出

2.

        

同上,第一句输出 我是A类,第二句hahah我是B类的有参构造,第三句我是c类的有参构造,第四句我是c类的无参构造

3.

        

package com.hspedu.extend_.exercise;


public class ExtendsExercise03 {
    public static void main(String[] args) {
        PC pc = new PC("intel","16","500","IBN");
        NotePad notePad = new NotePad("intel","16","500","yellow");
        pc.infoPrint();
        notePad.infoPrint();
    }
}
class Computer{
    private String CPU;
    private String memory;
    private String disk;

    public Computer(String CPU, String memory, String disk) {
        this.CPU = CPU;
        this.memory = memory;
        this.disk = disk;
    }

    public String getCPU() {
        return CPU;
    }


    public String getMemory() {
        return memory;
    }


    public String getDisk() {
        return disk;
    }

    public String getDetails(){
        return CPU + " " + memory + " " + disk;
    }


}
class PC extends Computer{
    private String brand;

    public PC(String CPU, String memory, String disk, String brand) {
        super(CPU, memory, disk);// 执行父类初始化,并给值
        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }

    public void infoPrint(){
        System.out.println(getDetails() + " " + getBrand());
    }
}
class NotePad extends Computer{
    String color;

    public NotePad(String CPU, String memory, String disk, String color) {
        super(CPU, memory, disk); // 执行父类初始化,并给值
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void infoPrint(){
        System.out.println(getDetails() + " " + getColor());
    }
}

要考虑使用另一个带项目包的写文章方式了,byd写一下几千字进去了

        ​​​​​​​​​​​​​​        

注意,父类的构造器由父类来执行,而不要在子类赋值初始化,同理使用构造器进行对属性的赋值,而不是赋值,赋值要用setXxx方法执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yinhai1114

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

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

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

打赏作者

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

抵扣说明:

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

余额充值