java继承和多态详解

简介: java继承和多态详解

前言

继承和多态刚开始是比较难理解的,要做到多看,多敲代码。

一、继承

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

为了方便理解,我们先看下面一段代码。

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

// Animal.java 
public 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 + "正在飞 ︿( ̄︶ ̄)︿"); 
    }

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

1)这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的.

2)这三个类都具备一个相同的 name 属性, 而且意义是完全一样的.

(2)语法规则

class 子类 extends 父类 { 
} 

对于上面的代码, 可以使用继承进行改进. 此时我们让 Cat 和 Bird 继承自 Animal 类, 那么 Cat 在定义的时候就不必再写 name 字段和 eat 方法。

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方法.

(3)注意

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

(4)字段和方法访问权限

private: 类内部能访问, 类外部不能访问

默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.

protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.

public : 类内部和类的调用者都能访问

二、多态

首先需要实现多态需要满足一些条件:

1) 继承关系上满足向上转型

2)子类和父类 有同名的覆盖/重写方法

3)通过父类对象的引用去调用这个重写的方法

完成以上三步就会发生动态绑定,动态绑定是多态的基础.

一、向上转型

(1)在刚才的例子中, 我们写了形如下面的代码

Bird bird = new Bird("圆圆"); 

这个代码也可以写成这个样子

Bird bird = new Bird("圆圆"); 
Animal bird2 = bird; 
// 或者写成下面的方式 
Animal bird2 = new Bird("圆圆"); 

此时 bird2 是一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例. 这种写法称为 向上转型.

(2)向上转型方法有三种

1)直接赋值

Animal animal = new Dog("圆圆",7);

2)方法的参数,传参是向上转型

public static void funcl(Animal animal){
}
public static void main(String[] args){
  Dog dog = new Dog("圆圆",6);
  func1(dog);
}

3)返回值向上转型

public static Animal func2(){
  Dog dog = new Dog("圆圆",19);
  return dog;
}

二、重写

针对刚才的 eat 方法来说:

子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).

(1)关于重写的注意事项

1)最基本的返回值 参数列表 方法名必须是一样的

2)被重写的方法的访问修饰限定符在子类中要大于等于父类的

3)被private修饰的方法不可以被重写的

4)被static修饰的方法是不可以被重写的

5)被final修饰的方法是不可以被重写的

三、动态绑定

子类和父类中出现同名方法的时候, 再去调用会出现什么情况呢?

对前面的代码稍加修改, 给 Bird 类也加上同名的 eat 方法, 并且在两个 eat 中分别加上不同的日志.

// Animal.java 
public class Animal { 
    protected String name; 
    public Animal(String name) { 
        this.name = name; 
    } 
    public void eat(String food) { 
        System.out.println("我是一只小动物"); 
        System.out.println(this.name + "正在吃" + food); 
    } 
} 
// Bird.java 
public class Bird extends Animal { 
    public Bird(String name) { 
        super(name); 
    } 
    public void eat(String food) { 
        System.out.println("我是一只小鸟"); 
        System.out.println(this.name + "正在吃" + food); 
    } 
} 
// Test.java 
public class Test { 
    public static void main(String[] args) { 
        Animal animal1 = new Animal("圆圆"); 
        animal1.eat("谷子"); 
        Animal animal2 = new Bird("扁扁"); 
        animal2.eat("谷子"); 
    } 
} 
// 执行结果 
我是一只小动物 
圆圆正在吃谷子 
我是一只小鸟 
扁扁正在吃谷子 

此时, 我们发现:

animal1 和 animal2 虽然都是

Animal 类型的引用, 但是 animal1 指向

Bird 类型的实例.

针对 animal1 和 animal2 分别调用 eat 方法, 发现

animal2.eat() 实际调用了子类的方法

四、多态的好处

类调用者对类的使用成本进一步降低.

封装是让类的调用者不需要知道类的实现细节.

多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可

相关文章
|
27天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
3天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
374 16
|
19天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
6天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
21天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
23天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2595 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
5天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
183 2
|
3天前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
105 65
|
7天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
333 2
|
23天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1580 17
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码