面向对象编程之继承(超详细)

一.继承的引入(为什么要继承)

1.1引入

我们举一个很常见的例子,在进入社会之前,我相信很多人都有过学生的经历,那么我们身为学生大概都会就会经历小学、初中、高中、大学、研究生、博士生......

每个阶段都有考试,我们的成绩单都会对应自己姓名加成绩,那么我要写一个程序打出我从小学到博士生毕业成绩,显然这其中会有很多的重复代码,那么我们为什么不可以把重复的写到一个类中,然后再各自调用呢,这样看起来就方便很多,于是引出继承。

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

1.2示意图

示意图中父子类是相对关系,B可以说是D的父类,也可以说是A的子类。

1.3继承基本语法

class 子类 extends 父类{}

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

父类又叫超类、基类;

子类又叫派生类;

1.4继承给编程带来的便利

1) 代码的复用性提高了
2) 代码的扩展性和维护性提高了

二.继承的深入讨论/细节问题(10条)

2.1继承访问限制

1)子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问 , 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
准备工作,我们创建基类Base,子类Sub进行测试
public class Base {
    public int n1 = 10;
    protected int n2 = 20;
    int n3 = 30;
    private int n4 = 40;
    public Base(){
        System.out.println("父类 Base()构造器被调用....");
    }
    public void test10(){
        System.out.println("test10");
    }
    protected void test20(){
        System.out.println("test20");
    }
    void test30(){
        System.out.println("test30");
    }
    private void test40(){
        System.out.println("test40");
    }
}
public class Sub extends Base{
    public Sub() {
        System.out.println("子类 Sub()构造器被调用....");
    }
}

我们可以看到,private是不允许被调用的,我们可以使用get方法声明一个公开的来调用(在基类中)

public void getN4() {
        System.out.println(n4);
    }

那么我们就可以通过调用getN4来输出n4的值了。

2.2super引入

2)子类必须调用父类的构造器, 完成父类的初始化
3) 当创建子类对象时,不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器 ,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过(怎么理解。) [举例说明]
4) 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super( 参数列表 )
5) super 在使用时,必须放在构造器第一行 (super 只能在构造器中使用 )
6) super() this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
public class Base {
    public int n1 = 10;
    protected int n2 = 20;
    int n3 = 30;
    private int n4 = 40;
    public Base(){
        System.out.println("父类 Base()构造器被调用....");
    }

    public Base(int n1, int n2) {
        this.n1 = n1;
        this.n2 = n2;
        System.out.println("父类 Base(int n1, int n2)构造器被调用....");
    }

基类中有两个构造器

public class Sub extends Base{
    public Sub() {
        System.out.println("子类 Sub()构造器被调用....");
    }
}

子类中一个无参构造器

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

创建对象,会完成父类的初始化,但是我们看运行结果,发现,它打印的是基类中的无参方法,这里其实在Sub构造器中隐藏了super,没有指定时候,它会默认指定为基类中的无参构造器。

指定特定构造器看结果

7) java 所有类都是 Object 类的子类 , Object 是所有类的基类 .
8) 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object ( 顶级父类 )
9) 子类最多只能继承一个父类 ( 指直接继承 ) ,即 java 中是单继承机制。 思考:如何让 A 类继承 B 类和 C 类? 【 A 继承 B B 继承 C
10) 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系(例如猫类不可以继承汽车类)

三.继承本质

当子类对象创建好后,建立查找关系

(1) 首先看子类是否有该属性
(2) 如果子类有这个属性,并且可以访问,则返回信息
(3) 如果子类没有这个属性,就看父类有没有这个属性 ( 如果父类有该属性,并且可以访问,就返回信息 ..)
(4) 如果父类没有就按照 (3) 的规则,继续找上级父类,直到 Object..

3.1案例详析

public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println(son.name);//返回的是儿子的name
        son.age;//不会继续往爷爷哪里找,爸爸私有,就会堵在这里
    }
}
class GrangPa {
    String name = "大头爷爷";
    String hobby = "旅游";
}
class Father extends GrangPa {
    String name = "大头爸爸";
    private int age = 80;
}
class Son extends Father {
    String name = "大头儿子";
}

我们的age是私有的,访问受限,报错

3.2分析图

四.用到的快捷键

ctrl+b 追溯

ctrl+h 继承图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小白初级

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

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

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

打赏作者

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

抵扣说明:

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

余额充值