写点什么

Java | extends 关键字【面向对象的第二大特征——继承】

作者:Fire_Shield
  • 2022 年 9 月 23 日
    浙江
  • 本文字数:5434 字

    阅读完需:约 18 分钟

Java | extends关键字【面向对象的第二大特征——继承】

@TOC

一、继承的概念引入

1、继承是什么?有什么好处?

所谓继承,它是 java 面向对象编程技术的一块基石,有了这块基石,我们便可以通过==extends==关键字让一个类和另一个类建立起一个父子关系


对于继承的好处,主要有以下三点:point_down:


  • 可以提高代码复用性【将共同的功能统一写在一个父类中】

  • 减少代码冗余【同一个功能无需多写,继承自父类即可】

  • 增强类的功能扩展性【子类可以重写父类中的普通方法】

2、怎么继承?格式是怎样的?

对于怎么继承,既然本文讲 extends 关键字,那一定是使用 extends 来继承自一个父类


具体的模式写法如下


class 父类{...}
复制代码


class 子类 extends 父类{...}
复制代码

3、继承之后会怎样呢?

在继承之后,子类便可以得到父类的属性(成员变量)和行为(各种方法),而且在此基础上,子类还可以继续增加属于自己的功能


  • 所以都说子类比父类强大,确实是这样,有一句话说得也和这个继承的关系类型,那就是长江后浪推前浪,浮事新人换旧人

4、Java 继承与 C++继承的区别

说完以上三点,相信大家对继承也有了一个初步地了解,如果有学过 C++的小伙伴肯定也知道,在 C++中也有继承,那对于继承在 Java 和 C++中有什么不一样呢,我们来探索一下:mag:


  • 对于 C++,可以进行多继承,意思就是一个子类可以有多个父类

  • 对于 Java,只有单继承,不可以进行多继承,但是 Java 可以像 C++那样实现多重继承,意思就是 B 类继承了 A 类,而且 C 类又继承了 B 了,我们管 C 类叫做 A 类的子孙类

  • 其实在 Java 中也是可以进行多继承的,但是它不叫多继承,它叫多接口,意思就是一个类可以有同时实现多个接口,接口中也有一些方法可供实现类进行重写,主要用到 implement 关键字,这个我们在后续会讲到

二、简单案例 &继承后的内存原理

说完了继承的基本概念,下面我们到编译器中带大家先看一个简单案例观察一下继承到底是怎么样的:computer:


People 父类


public class People {    private String name;    private int age;
//共同行为 public void queryCourse(){ System.out.println(name + "在查看课表"); } /** 父类对外获取私有私有成员变量的方法 */ 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; }}
复制代码


Teacher 子类


public class Teacher extends People{    int run;    void teach()    {        System.out.println("教书育人");    }}
复制代码


Student 子类


public class Student extends People{    int eat;    void study()    {        System.out.println("努力学习");    }}
复制代码


test 测试类


public class test {    public static void main(String[] args) {        Teacher t = new Teacher();        t.setName("王老师");        System.out.print(t.getName() + "在");        t.teach();

Student s = new Student(); s.setName("小明"); System.out.print(s.getName() + "在"); s.study();
System.out.println("----------"); t.queryCourse(); s.queryCourse(); }}
复制代码


运行结果


1、简要分析

  • 从上述代码来看,有一个 People 类作为父类,然后 Teacher 类和 Student 类作为 People 类的子类。观看 People 类,有两个私有成员变量和一些父类对外获取私有私有成员变量的方法,然后又看到了一个子类所拥有的共同行为这个方法,可供其所有子类调用

  • 然后两个子类中有它们各自在继承了父类的属性和行为后新增的独有功能

  • 透过测试类和运行结果我们不难发现,两个子类所创建的对象都完成了他么自己独有的功能,而且他们还完成了相同的功能

2、内存原理剖析


  • 从这张堆内存的原理图可以看出,在子类继承完父类之后,在子类的堆内存空间中会有被分为两块区域,一块是从父类继承而来的,我们通常称为 super,一块是子类存放自己变量和方法的区域,通常称为 this

  • 但我们也不用刻意去区别这个东西,只要心中有数就行,子类继承过来之后会分为两块空间存储变量和方法

三、子类继承父类后的特性

1、基本特性

  • 子类可以继承父类的属性和行为,但是子类不能继承父类的构造器

  • Java 是单继承模式 :一个类只能继承一个直接父类

  • Java 不支持多继承,但是支持多层继承,这个我们在上面有讲到过

  • 而且 Java 中所有的类都是 Object 类的子类,这个的话可以去看官方给的 API 文档,我的是最新的 JDK18


例如这个 Array 类,就是继承自 Object 一个总的对象类


2、隐藏特性

  • 子类不能继承父类的构造器

  • 子类可以继承父类的私有成员,但只是不能访问

  • 子类不可以继承父类的静态成员,只是共享


具体地实现我们到代码里来看看


public class Test {    public static void main(String[] args) {        //1.子类不能继承父类的构造器        //2.子类可以继承父类的私有成员吗? -  可以继承,但只是不能访问        Tiger t = new Tiger();        //t.eat();        //3.子类可以继承父类的静态成员吗 -  不可以,只是共享        //比如你爸爸把车给你开,但是这个车还是你爸爸的        System.out.println(Tiger.location);        //静态成员用类访问    }}
class Animal extends Object{ //Object类是默认继承的 private void eat(){ System.out.println("动物正在吃东西~~"); } public static String location = "长隆动物园";}
class Tiger extends Animal{
}
复制代码


  • 好,我们来详细说明一下二三两点,关于父类的私有成员,子类是肯定不能访问的,但是在 Java 的底层,其实子类是继承了父类的私有成员的,对于访问的话是不可以直接访问的,但是可以通过父类的 get()方法来访问。这样讲述可能还是有点抽象

  • 【例如说你爸爸给了你一个保险箱,但是只是把箱子给了你,你继承了这个箱子,但是呢你又打不开,无法看到里面有什么东西,这个时候就需要你爸爸给你一把钥匙是打开这个箱子,这个钥匙就好比是父类提供的访问给子类访问自己私有成员变量的对外接口】

  • 然后是对于第三点,子类可以继承父类的静态成员吗?答案是否,虽然说静态的东西大家都可以访问,但是对于子类来说,却不能继承父类的静态成员,无论是成员变量或是成员方法,再举个例子

  • 【你爸爸把他开了三四年的车借你一个刚考出驾照的人开,那这个车会直接是你的吗?有直接给到你吗?或许不会,这只是一个共享,并没有真正地得到,再说你爸也不会傻到把车送个一个新手司机开吧:point_left:】

3、成员变量与成员方法的访问机制

好,说完了子类继承父类后的一些属性和特性,我们再来详细说一下成员变量和成员方法的一个访问机制


  • 对于这个访问机制其实就四个字:【就近原则】


public class Test {    public static void main(String[] args) {        Dog d = new Dog();        d.lookdoor();        d.run();    }}
复制代码


class Animal{    public void run(){        System.out.println("动物会跑~~");    }}
复制代码


class Dog extends Animal{    public void lookdoor(){        System.out.println("狗会看门");    }}
复制代码



  • 从上述代码可以看出,我们在 Animal 动物类中定义类一个 run()方法,然后在主方法中调用,结果就显示的是【动物会跑】,然后调用 lookdoor()就是【狗会看门】


class Dog extends Animal{    public String name = "汪汪";
public void lookdoor(){ System.out.println("狗会看门"); } public void run() { System.out.println("狗跑得贼快"); }}
复制代码



  • 但是又通过一个子类 Dog 去继承父类后,在子类中有声明了一个 run()方法,这时在主方法显示的便是调用子类所声明的 run()方法


以上就是成员方法的调用机制,接下来说说成员变量


  • 在 Dog 子类中,我写了一个 showname 的方法,然后,定义了一个姓名的成员变量和一个局部变量,现在假设我们没有局部变量,那主方法访问的便是【汪汪】,但如果加上局部变量【名字】,那就会优先访问局部变量



class Dog extends Animal{    public String name = "汪汪";    public void showname(){        String name = "名字";        System.out.println(name);    }    public void lookdoor(){        System.out.println("狗会看门");    }    public void run() {        //super.run();        System.out.println("狗跑得贼快");    }}
复制代码


  • 但是这样的话我们要怎么访问成员变量和父类中的成员变量呢,这里就要使用到我们开头有提到够的【this】和【super】关键字,==有关这两个关键字之后我会做再写一篇文章做详细讲解==


class Animal{    public String name = "叫声";    public void run(){        System.out.println("动物会跑~~");    }}
复制代码


class Dog extends Animal{    public String name = "汪汪";    public void showname(){        String name = "名字";        System.out.println(name);        System.out.println(this.name);      //访问当前子类对象name        System.out.println(super.name);     //访问当前父类对象name    }    public void lookdoor(){        System.out.println("狗会看门");    }    public void run() {        //super.run();        System.out.println("狗跑得贼快");    }}
复制代码



  • 从运行结果我们可以看出,通过直接访问和两个关键字的访问,我们都得到了想要的结果

四、子类方法重写【override 关键字】

对于子类继承自一个父类,并且获取了父类中的一些成员方法,但是我们说过子类功能是强于父类的,原因是子类可以通过【override】关键字来重写父类中的成员方法

1、重写父类方法的规则

  • 重写方法的名称、形参列表必须和父类的一样

  • 子类重写父类方法时,访问权限必须大于或者等于父类被重写的方法的权限,不允许降低方法的访问权限

  • 不可重写父类的静态方法

2、具体案例展示

University 父类


public class University {    void admit(double chinese, double math, double  english){        double aggregate = chinese + math + english;        if(aggregate >= 200)            System.out.println(aggregate + "\t双非过线了!!!");        else            System.out.println(aggregate + "\t双非没过线~~>_<~~");    }}
复制代码


ImportantUniversity 子类


public class ImportantUniversity extends University{    @Override    //1.重写校验注解,加上之后,这个方法必须是正确重写的,更安全                    //2.提高程序的可读性,代码优雅    void admit(double chinese, double math, double english) {        double aggregate = chinese + math + english;        if(aggregate >= 240)            System.out.println(aggregate + "\t211过线了!!!");        else            System.out.println(aggregate + "\t211没过线~~>_<~~");    }}
复制代码


C9ImportantUniversity 子孙类


public class C9ImportantUniversity extends ImportantUniversity{    @Override    void admit(double chinese, double math, double english) {        double aggregate = chinese + math + english;        if(aggregate >= 270)            System.out.println(aggregate + "\t985过线了!!!");        else            System.out.println(aggregate + "\t985没过线~~>_<~~");    }}
复制代码


test 测试类


public static void main(String[] args) {    double chinese = 80;    double math = 90;    double english = 98;    University university = new University();    university.admit(chinese, math, english);
ImportantUniversity g = new ImportantUniversity(); g.admit(chinese, math, english);
C9ImportantUniversity gg = new C9ImportantUniversity(); gg.admit(chinese, math, english);}
复制代码


运行结果



  • 好我们来看一下这个案例,这是一个高考录取分数的案例,父类为双非本科院校,子类为 211 重点大学,子孙类为 985 的 C9 联盟高校,从运行结果我们可以看出,通过不同类声明的对象去调用,展现出的是各自类不同的特性

  • 可以看到这里的子类去重写父类的成员方法时,用到了 @override,其实这个关键字时可以省略的,也不会报错。但是加上这个关键字之后有两点好处:一点是编译器后台后自动判断这个方法必须是正确重写的,更安全,第二点是可以提高程序的可读性,使得你书写的代码优雅更加优雅

3、注意事项

  • 这个我们在上面对于重写的基本规则里有提到,就是在重写父类方法的时候,不允许降低方法的访问权限,但是可以提高方法的访问权限,具体的访问权限按从高到低排列是这样的【public > protected > 缺省(友好的)> private

  • 所以大家在通过子类去重写父类方法的时候,不要出现父类中的方法是 public 的,但是你重写之后变成了 protected

五、技术小结与回顾

通过本文的阅读,您是否有对 Java 中的 extends 关键字有了一个比较全面的认识,这个关键字主要是体现在==面向对象的第二大特征——继承==,之后还会继续出品 Java 中其他关键字和对应知识点的说明,例如多态的 abstruct 关键字接口的 implements 关键字,记得关注我哦:cherry_blossom:


若本文有任何疑问,可以于评论区留言或者私信我,感谢您对本文的观看,以下是我开创的社区,感兴趣的小伙伴们可以加入进来一起交流学习,解决编程的难题


我的社区::fire:烈火神盾:fire:


发布于: 2022 年 09 月 23 日阅读数: 46
用户头像

Fire_Shield

关注

语言观决定世界观 2022.09.02 加入

高校学生,热爱编程,喜欢写作

评论

发布
暂无评论
Java | extends关键字【面向对象的第二大特征——继承】_Java_Fire_Shield_InfoQ写作社区