前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java的继承

Java的继承

作者头像
鲜于言悠
发布2024-05-31 12:52:48
550
发布2024-05-31 12:52:48
举报
文章被收录于专栏:c/c++的学习笔记c/c++的学习笔记
Java的继承

  • 前言
  • 一、继承是什么
    • 简介
    • 背景
    • 示例
  • 二、继承的语法规则
    • 基本语法
    • 改写Animal
  • 三、protected 关键字
    • 简介
    • 总结
      • 什么时候下用哪一种呢
  • 四、更复杂的继承关系
    • final 关键字
  • 五、拓展
    • 组合
      • 组合表示 has - a 语义
      • 继承表示 is - a 语义

前言

推荐一个网站给想要了解或者学习人工智能知识的读者,这个网站里内容讲解通俗易懂且风趣幽默,对我帮助很大。我想与大家分享这个宝藏网站,请点击下方链接查看。 https://www.captainbed.cn/f1

Java的继承是一种面向对象编程的核心概念,允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法,从而实现代码的重用和扩展。通过继承,子类可以继承父类的所有非私有属性和方法,并可以添加或覆盖自己的属性和方法,以实现特定的功能。这种机制提高了代码的复用性和可维护性。


一、继承是什么

简介

Java的继承是面向对象编程中的一个重要概念。它允许一个类(称为子类)继承另一个类(称为父类)的属性和方法。

继承通过创建类之间的关系,使得子类可以重用父类的代码,并且可以在不修改父类的情况下添加新的功能。当一个类继承自另一个类时,它继承了父类的公共属性和方法,并且可以添加自己的特定属性和方法。被继承的类被称为超类或基类,继承的类被称为子类或派生类。子类可以访问父类的公有和受保护的成员,但不能访问父类的私有成员。通过继承,可以实现代码的重用、层次化管理和多态性等特性。

背景

代码中创建的类, 主要是为了抽象现实中的一些事物(包含属性和方法).

有的时候客观事物之间就存在一些关联关系, 那么在表示成类和对象的时候也会存在一定的关联.

示例

例如, 设计一个类表示动物

注意, 我们可以给每个类创建一个单独的 java 文件. 类名必须和 .java 文件名匹配(大小写敏感).

代码语言:javascript
复制
// Animal
//
class Animal {
    public String name;
    public Animal(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
    }
}

// Cat.java 
class Cat {
    public String name;

    public Cat(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
    }
}

// Bird.java 
class Bird {
    public String name;

    public Bird(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
    }

    public void fly() {
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
    }
}

这个代码我们发现其中存在了大量的冗余代码.

仔细分析, 我们发现 AnimalCat 以及 Bird 这几个类中存在一定的关联关系:

  • 这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的.
  • 这三个类都具备一个相同的 name 属性, 而且意义是完全一样的.
  • 从逻辑上讲, CatBird 都是一种 Animal (is - a 语义).

此时我们就可以让 CatBird 分别继承 Animal 类, 来达到代码重用的效果.

此时, Animal 这样被继承的类, 我们称为 父类 , 基类 或 超类, 对于像 CatBird 这样的类, 我们称为 子类, 派生类和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段和方法, 以达到代码重用的效果.

二、继承的语法规则

基本语法

代码语言:javascript
复制
class 子类 extends 父类 { 
 
} 
  • 使用 extends 指定父类.
  • Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
  • 子类会继承父类的所有 public 的字段和方法.
  • 对于父类的 private 的字段和方法, 子类中是无法访问的.
  • 子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用.

改写Animal

对于上面的代码, 可以使用继承进行改进.

此时我们让 CatBird 继承自 Animal 类, 那么 Cat 在定义的时候就不必再写 name 字段和 eat 方法.

代码语言:javascript
复制
public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
    }
}

class Cat extends Animal {
    public Cat(String name) {
        // 使用 super 调用父类的构造方法. 
        super(name);
    }
}

class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }

    public void fly() {
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
    }
}

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat("小黑");
        cat.eat("猫粮");
        Bird bird = new Bird("圆圆");
        bird.fly();
    }
} 

extends 英文原意指 “扩展”. 而我们所写的类的继承, 也可以理解成基于父类进行代码上的 “扩展”.

例如我们写的 Bird 类, 就是在 Animal 的基础上扩展出了 fly 方法.

如果我们把 name 改成 private, 那么此时子类就不能访问了.

代码语言:javascript
复制
class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }

    public void fly() {
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
    }
}

// 编译出错 
Error:(19, 32) java: name 在 Animal 中是 private 访问控制 

三、protected 关键字

简介

刚才我们发现, 如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 “封装” 的初衷.

  • 两全其美的办法就是 protected 关键字.
  • 对于类的调用者来说, protected 修饰的字段和方法是不能访问的

对于类的 子类 和 同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的

代码语言:javascript
复制
public class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
    }
}

// Bird.java 
public class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }

    public void fly() {
        // 对于父类的 protected 字段, 子类可以正确访问 
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
    }
}

// Test.java 和 Animal.java 不在同一个 包 之中了. 
public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal("小动物");
        System.out.println(animal.name); // 此时编译出错, 无法访问 name 
    }
}  

总结

Java 中对于字段和方法共有四种访问权限

  • private: 类内部能访问, 类外部不能访问
  • 默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
  • protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
  • public : 类内部和类的调用者都能访问
在这里插入图片描述
在这里插入图片描述
什么时候下用哪一种呢

我们希望类要尽量做到 “封装”, 即隐藏内部实现细节, 只暴露出 必要 的信息给类的调用者.

因此我们在使用的时候应该尽可能的使用 比较严格 的访问权限. 例如如果一个方法能用 private, 就尽量不要用public.

另外, 还有一种 简单粗暴 的做法: 将所有的字段设为 private, 将所有的方法设为 public. 不过这种方式属于是对访问权限的滥用, 还是更希望读者们能写代码的时候认真思考, 该类提供的字段方法到底给 “谁” 使用(是类内部自己用, 还是类的调用者使用, 还是子类使用).

四、更复杂的继承关系

刚才我们的例子中, 只涉及到 Animal, CatBird 三种类. 但是如果情况更复杂一些呢?

针对 Cat 这种情况, 我们可能还需要表示更多种类的猫

在这里插入图片描述
在这里插入图片描述

这个时候使用继承方式来表示, 就会涉及到更复杂的体系.

代码语言:javascript
复制
// Animal.java 
public Animal { 
 ... 
} 
 
// Cat.java 
public Cat extends Animal { 
 ... 
} 
 
// ChineseGardenCat.java 
public ChineseGardenCat extends Cat { 
 ... 
} 
 
// OrangeCat.java 
public Orange extends ChineseGardenCat { 
 ... 
} 
...... 

如刚才这样的继承方式称为多层继承, 即子类还可以进一步的再派生出新的子类.

时刻牢记, 我们写的类是现实事物的抽象. 而我们真正在生活中所遇到的项目往往业务比较复杂, 可能会涉及到一系列复杂的概念, 都需要我们使用代码来表示, 所以我们真实项目中所写的类也会有很多. 类之间的关系也会更加复杂.

但是即使如此, 我们并不希望类之间的继承层次太复杂. 一般我们不希望出现超过三层的继承关系. 如果继承层次太多, 就需要考虑对代码进行重构了.

如果想从语法上进行限制继承, 就可以使用 final 关键字

final 关键字

final 关键字, 修饰一个变量或者字段的时候, 表示 常量 (不能修改).

代码语言:javascript
复制
final int a = 10; 
a = 20; // 编译出错

final 关键字也能修饰类, 此时表示被修饰的类就不能被继承.

代码语言:javascript
复制
final public class Animal { 
 ... 
} 
 
public class Bird extends Animal { 
 ... 
} 
 
// 编译出错 
Error:(3, 27) java: 无法从最终com.bit.Animal进行继承 

final 关键字的功能是 限制 类被继承

“限制” 这件事情意味着 “不灵活”. 在编程中, 灵活往往不见得是一件好事. 灵活可能意味着更容易出错.

是用 final 修饰的类被继承的时候, 就会编译报错, 此时就可以提示我们这样的继承是有悖这个类设计的初衷的.

在这里插入图片描述
在这里插入图片描述

我们平时是用的 String 字符串类, 就是用 final 修饰的, 不能被继承.

五、拓展

组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.

例如表示一个学校:

代码语言:javascript
复制
public class Student { 
 ... 
} 
 
public class Teacher { 
 ... 
} 
 
public class School { 
 public Student[] students; 
 public Teacher[] teachers; 
} 

组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段.

这是我们设计类的一种常用方式之一.

组合表示 has - a 语义

在刚才的例子中, 我们可以理解成一个学校中 “包含” 若干学生和教师.

继承表示 is - a 语义

在上面的 “动物和猫” 的例子中, 我们可以理解成一只猫也 “是” 一种动物.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java的继承
  • 前言
  • 一、继承是什么
    • 简介
      • 背景
        • 示例
        • 二、继承的语法规则
          • 基本语法
            • 改写Animal
            • 三、protected 关键字
              • 简介
                • 总结
                  • 什么时候下用哪一种呢
              • 四、更复杂的继承关系
                • final 关键字
                • 五、拓展
                  • 组合
                    • 组合表示 has - a 语义
                    • 继承表示 is - a 语义
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档