JavaSE(多态、abstract、接口)

news2024/11/13 10:20:24

1.多态

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。

向上转型

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:**父类类型 对象名 = new 子类类型()**这种是【直接赋值法】

Animal animal = new Dog( );
animal是父类类型,但可以引用一个子类对象,因为是从小范围向大范围的转换。

除了这种方式还有两种:

  1. 方法传参
    在这里插入图片描述

  2. 方法返回

public static Animal func(){
	return new dog();
}
public static void main(Sting[] args){
	func();
}

在这里插入图片描述

重写

重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程
进行重新编写
, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

【方法重写的规则】

  • 子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致
  • 被重写的方法返回值类型可以不同,但是必须是具有父子关系的
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方 法就不能声明为 protected
  • 父类被static、private修饰的方法、构造方法都不能被重写。
  • 重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心 将方法名字拼写错了
    (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法 构成重写.
    在这里插入图片描述
    【重写和重载的区别】
    即:方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
    在这里插入图片描述

例子

 有了面的向上转型, 动态绑定, 方法重写之后, 我们就可以使用 多态(Polymorphism) 的形式来设计程序。
class Shape{// 无论是 三角形,还是正方形等等,它们都是图形
    // 以此作为共性抽出
    public void draw(){
        System.out.println("Shape::draw()");
    }
}
// 矩形
class Rect extends Shape{
    @Override// 当我们在子类中,重写了父类中的方法。那么父类方法中的输出语句就显得毫无意义
    // 最后都是输出子类draw方法,如果你想的话,可以删掉父类的 输出语句
    public void draw(){
        System.out.println("♦");
    }
}
// 花
class Flower extends Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}

public class Test {
    public static void paint(Shape shape){
        shape.draw();
    }
    public static void main(String[] args) {
        Rect rect = new Rect();
        paint(rect);
        paint(new Rect());
        System.out.println("=============");
        Flower flower = new Flower();
        paint(flower);
        paint(new Flower());
    }
 }

从另一个方面来说:通过一个引用来调用不同的draw方法,会呈现出不同的表现形式。表现的形式取决于将来它引用那个对象。这就是动态。而且实现多态的大前提,就是一定要向上转型,且实现 父类和子类的重写方法。

总结:

在这个代码中, 上方的代码(矩形、花、继承)是 类的实现者 编写的, 下方的代码(main所在的类)是 类的调用者 编写的。当类的调用者在编写 Paint 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当前的 shape。
引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现。(和 shape 对应的实例相关), 这种行为就称为 多态。
多态 顾名思义, 就是 “一个引用, 能表现出多种不同形态

2.抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果
一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

// 抽象类:被abstract修饰的类
public abstract class Shape {
    // 抽象方法:被abstract修饰的方法,没有方法体
    abstract public void draw();
    abstract void calcArea();
 
    // 抽象类也是类,也可以增加普通方法和属性
    public double getArea(){
        return area;
    }
 
    protected double area;    // 面积
}

抽象类和普通类的区别?
1.抽象类 使用abstract修饰;
2.抽象类不能被实例化;(不能new)
3.此时在抽象类中,可以有抽象方法,或者 非抽象方法
4.什么是抽象方法。一个方法被abstract修饰,没有具体的实现。只要包含抽象方法,这个类必须是抽象类。
5.当一个普通类继承了这个抽象类,必须重写抽象类当中的抽象方法。
6.抽象类存在的最大的意义,就是为了被继承。
7.抽象方法不能被private、final、static,所以,一定要满足方法重写的规则
8.当一个子类没有重写抽象父类的方法,可以把当前子类变为abstract修饰。
9.抽象类当中不一定包含抽象方法。
10.抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量。

抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.
普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法呢?
确实如此. 但是使用抽象类相当于多了一重编译器的校验(如果你没有重写抽象方法,编译器会报错,提醒你)

3.接口

在现实生活中,接口的例子比比皆是,比如:笔记本上的USB口,电源插座等。
接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。
在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量

语法规则

接口的定义格式与定义类的格式基本相同,将class关键字换成interface 关键字,就定义了一个接口。

提示:

  1. 创建接口时, 接口的命名一般以大写字母 I 开头.
  2. 接口的命名一般使用 “形容词” 词性的单词.
  3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.
public interface 接口名称{
    // 抽象方法
    public abstract void method1();   // public abstract 是固定搭配,可以不写
    public void method2();
    abstract void method3();
    void method4();
    // 注意:在接口中上述写法都是抽象方法,跟推荐方式4,代码更简洁
    }
    

接口使用

接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法
public class 类名称 implements 接口名称{...}
注意:子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系

接口特性

  1. 接口类型是一种引用类型,但是不能直接new接口的对象
public class TestUSB {
    public static void main(String[] args) {
        USB usb = new USB();
    }
}
 
// Error:(10, 19) java: day20210915.USB是抽象的; 无法实例化
  1. 接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为
    public abstract(只能是public abstract,其他修饰符都会报错)
public interface USB {
    // Error:(4, 18) java: 此处不允许使用修饰符private
    private void openDevice();
    void closeDevice();
}
  1. jdk8中:接口中还可以包含default方法
public interface USB {
    default void closeDevice();
}
  1. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
public interface USB {
    void openDevice();
  
    // 编译失败:因为接口中的方式默认为抽象方法
    void closeDevice(){
        System.out.println("关闭USB设备");
    }
}
  1. 重写接口中方法时,不能使用默认的访问权限
public interface USB {
    void openDevice();    // 默认是public的
    void closeDevice();   // 默认是public的
}
public class Mouse implements USB {
    @Override
    void openDevice() {
        System.out.println("打开鼠标");
    }
}
 
// 编译报错,重写USB中openDevice方法时,不能使用默认修饰符
// 正在尝试分配更低的访问权限; 以前为public

在这里插入图片描述

  1. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
public interface USB {
    double brand = 3.0;  // 默认被:final public static修饰
    void openDevice();
    void closeDevice();
}
 
public class TestUSB {
    public static void main(String[] args) {
        System.out.println(USB.brand);   // 可以直接通过接口名访问,说明是静态的
        
        // 编译报错:Error:(12, 12) java: 无法为最终变量brand分配值
        USB.brand = 2.0;       // 说明brand具有final属性
    }
}


  1. 接口中不能有静态代码块和构造方法
public interface USB {
    // 编译失败
    public USB(){
    }
    
    {}    // 编译失败 
    
    void openDevice();
    void closeDevice();
}
  1. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  2. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
  3. 当一个类实现接口之后,重写抽象方法的时候,重写方法的前面必
    须加上public,因为接口中方法默认都是public的,而且重写方法的访
    问权限,必须要大于等于父类当中方法的访问权限。
  4. 一个类可以通过关键字extends继承一个抽象类或者普通类。但是
    只能继承一个类。同时也可以通过implements实现多个接口。接口之
    间使用逗号隔开。
  5. 接口与接口之间,可以使用 extends来 操作它们的关系,此时,extends 在这里意为 拓展,而不是继承,(一个接口 通过 extends 来拓展 另一个接口的功能)
    在这里插入图片描述
    在这里插入图片描述
    由此得出结论:接口当中的方法(静态,和 默认),只能通过 接口的引用来调用

实现多个接口

在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承,但是一个类可以实现多个接口

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


另外我们再提供一组接口, 分别表示 “会飞的”, “会跑的”, “会游泳的”

interface IFlying {
    void fly();
}
 
interface IRunning {
    void run();
}
 
interface ISwimming {
    void swim();
}


接下来我们创建几个具体的动物 --猫, 是会跑的

class Cat extends Animal implements IRunning {
    public Cat(String name) {
        super(name);
    }
 
    @Override
    public void run() {
        System.out.println(this.name + "正在用四条腿跑");
    }
}

鱼, 是会游的


class Fish extends Animal implements ISwimming {
    public Fish(String name) {
        super(name);
    }
 
    @Override
    public void swim() {
        System.out.println(this.name + "正在用尾巴游泳");
    }
}

青蛙, 既能跑, 又能游(两栖动物)

class Frog extends Animal implements IRunning, ISwimming {
    public Frog(String name) {
        super(name);
    }
 
    @Override
    public void run() {
        System.out.println(this.name + "正在往前跳");
    }
 
    @Override
    public void swim() {
        System.out.println(this.name + "正在蹬腿游泳");
    }
}

还有一种神奇的动物, 水陆空三栖, 叫做 “鸭子”

class Duck extends Animal implements IRunning, ISwimming, IFlying {
    public Duck(String name) {
        super(name);
    }
 
    @Override
    public void fly() {
        System.out.println(this.name + "正在用翅膀飞");
 
    }
 
    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }
	@Override
	public void swim() {
        System.out.println(this.name + "正在漂在水上");
	}
}	

注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类。
提示, IDEA 中使用 ctrl + i 快速实现接口
继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性

接口间的继承

接口间的继承相当于把多个接口合并在一起.
这样设计有什么好处呢?
时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型, 而只关注某个类是否具备某种能力

在这里插入图片描述
在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的。
接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字

举例上面的青蛙是两栖动物:

interface IRunning {
    void run();
}
 
interface ISwimming {
    void swim();
}
 
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
 
}
 
class Frog implements IAmphibious {
...
}

通过接口继承创建一个新的接口 IAmphibious 表示 “两栖的”. 此时实现接口创建的 Frog 类, 就继续要实现 run 方法, 也需要实现 swim 方法.

抽象类和接口的区别

核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法.
如之前写的 Animal 例子. 此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此处的 Animal 只能作为一个抽象类, 而不应该成为一个接口.

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

抽象类存在的意义是为了让编译器更好的校验, 像 Animal 这样的类我们并不会直接使用, 而是使用它的子类. 万一不小心创建了 Animal 的实例, 编译器会及时提醒我们.
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/172550.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(牛客)小杜跑酷

链接:https://ac.nowcoder.com/acm/contest/49244/F?&headNavacm 来源:牛客网 题目描述 小杜又在玩游戏了!这回他玩的是跑酷游戏! 已知该跑酷地图长为n,有3层,可以理解为一张3n的地图。令人新奇的是&…

Shiro学习看这一篇文章就够了

第一章 Shiro简介 第1节 shiro介绍 1官网地址: http://shiro.apache.org/Apache Shiro 是一个功能强大,易于使用的Java安全框架,他执行认证、授权、加密、会话管理等功能,使用Shiro易于理解的API,使你能够轻松的保护任何应用,如移动端应用,大型web应用以及企业级应用. Shiro可…

当前主流的后端语言,谁能夺得桂冠,果然是后生可畏!

主流后端语言 如今编程语言遍地开花,烟花迷乱,小编整理了最流行的几种编程语言如下: 这几种语言都是经久不衰,占领着后端编程界的半壁江山。TIOBE上的语言排名: C、Java、python,C, C#鏖战榜首…

元宇宙浪潮下,数智人拒绝“标品”

作者 | 曾响铃 文 | 响铃说 在各地文博会、生活节等大型文娱活动上,在博物馆等各类场馆的线上平台,在企业与用户交互的窗口,在政务平台滚动政策宣讲片中,尤其是,在各大卫视的跨年晚会上…… 2022年末、2023年年初&a…

MyBatis Generator ORM层面的代码自动生成器

在日常开发工作中,我们往往需要自己去构建各种数据表所对应的持久化对象(POJO)、用于操作数据库的接口(DAO)以及跟 DAO 所绑定的对应 XML。这都是一些重复性的操作,不需要多大技术含量。MyBatis Generator工…

优思学院|Minitab中的子组大小应该怎样填写?

关于SPC中的均值极差控制图(X-bar-R Chart),都是质量管理和六西格玛最常用的工具之一,学生经常都会问及SPC和子组的问题。 所谓的子组(Subgroup),是指在同一组条件(包括人、机、物、…

人工智能辅助药物发现(2)苗头化合物筛选

目录AI辅助苗头化合物筛选概述AI辅助CPICPI数据库蛋白质和化合物的特征表示深度学习CPI预测经典Y型架构基于注意力的架构基于复合物的架构CPI性能评估苗头化合物筛选的发展前景挑战与趋势实际应用AI辅助苗头化合物筛选概述 新型小分子药物的开发通常从生物学家确定疾病靶标开始…

oracle数据库初始化问题及处理方法记录

环境: 服务器装机是redhat7.9+oracle19,用户是oracle,用户组dba 装机后进行初始化: 1.配置oracle用户环境变量:~/.bash_profile export ORACLE_SIDxxx export ORACLE_BASE/oracle/app/oracle export OR…

海康visionmaster-在WPF中使用Winform控件的方法

描述 环境:VM4.0.0 VS2013及以上 现象:在算子SDK开发过程中,用户如何使用封装好的Winform模板匹配等控件? 解答 首先添加对如下两个dll文件的引用:WindowsFormsIntegration.dll,System.Windows.Forms.…

深入MySQL字符编码与对照规则

前言 本篇和大家一起深入MySQL的字符集与对照规则,剖析下我们存储在MySQL中的字段是如何进行存储和校验比对的。 先看问题:unique key为什么失效了?拉齐共识:回顾下字符编码的基础知识,回炉下ASCII和Unicode。深入了解…

算法训练营 day22 二叉树 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的节点

算法训练营 day22 二叉树 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的节点 二叉搜索树的最近公共祖先 235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode) 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度…

第三章 逻辑与推理

命题逻辑谓词逻辑知识图谱推理因果推理 3.1 命题逻辑 逻辑和推理是基于知识的操作。 命题逻辑是应用一套形式化规则对以符号表示的描述性陈述进行推理的系统。在命题逻辑中,一个或真或假的描述性陈述被称为原子命题,对原子命题的内部结构不做任何解析。…

UnityC#的lock用法简记

UnityC#的lock用法简记简述代码实例一、单线程二、多线程无lock三、多线程使用lock死锁注意拓展lock->InvokeMonitor参考链接简述 多线程环境中,不使用lock锁,会形成竞争条件,导致错误。 使用lock锁可以保证当有线程操作某个共享资源时&a…

【ONE·C || 操作符详解】

总言 C语言:各种操作符的使用介绍。 文章目录总言1、算术操作符2、移位操作符2.1、整体介绍2.2、左移操作符2.3、右移操作符(逻辑右移、算术右移)3、位操作符3.1、整体介绍3.2、演示实例3.2.1、按位与3.2.2、按位或3.2.3、按位异或3.2.4、按位…

离线文章画像计算--Tfidf计算

2.4.2 Tfidf计算 2.4.2.1 目的 计算出每篇文章的词语的TFIDF结果用于抽取画像 2.4.2.2TFIDF模型的训练步骤 读取N篇文章数据文章数据进行分词处理TFIDF模型训练保存,spark使用count与idf进行计算利用模型计算N篇文章数据的TFIDF值 2.4.2.3 实现 想要用TFIDF进行…

【数据结构初阶(Java)】认识时间复杂度和空间复杂度

目录 前言: 1、算法效率 2、时间复杂度 1、大O的渐近表示法(不是一个准确的) 2、时间复杂度练习题(没有明确要求,计算的时间复杂度就是最坏情况下) 3、空间复杂度 前言: 如何衡量一个算法的…

Java中多线程wait和notify的用法

目录 一、wait和notify/notifyAll的由来 二、wait()方法 三、notify方法 3.1 notify的作用 3.2 wait和notify的 相互转换代码图 3.3 notifyAll 四、为什么需要notify和wait都需要上锁? 五、wait和sleep的对比 前言:由于线程之间是抢占式执行的&a…

Linux常用命令——tftp命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tftp 在本机和tftp服务器之间使用TFTP协议传输文件 补充说明 tftp命令用在本机和tftp服务器之间使用TFTP协议传输文件。 TFTP是用来下载远程文件的最简单网络协议,它其于UDP协议而实现。嵌入式linu…

RTMP协议封装H264和H265协议详解

RTMP协议封装H264和H265协议详解 文章目录RTMP协议封装H264和H265协议详解1 RTMP和FLV2 RTMP协议封装H264视频流2.1 RTMP发送AVC sequence header2.2 RTMP发送AVCC视频帧数据‘3 RTMP协议封装H265视频流1 RTMP和FLV 有关RTMP和FLV格式详细介绍可查看如下文章: http…

2022 Moonbeam的点点滴滴离不开社区支持

Moonbeam成为首个上线波卡的平行链已经有一周年🎂啦,这是一段疯狂的旅程🏍。 为了纪念这一时刻,我们通过公开数据来回顾这一年的众多里程碑、更新和整体发生的一切。 让我们来回顾一下Moonbeam在2022年取得了哪些成就吧。 &…