【Java】Java进阶学习笔记(四)—— 抽象类与接口

news/2024/3/28 23:33:11/文章来源:https://blog.csdn.net/weixin_43848614/article/details/128769409

【Java】Java进阶学习笔记(四)—— 抽象类与接口

  • 一、抽象类
    • 1、抽象类的概念
      • 抽象类的定义格式
    • 2、抽象类的注意点
      • 抽象方法的介绍
    • 3、抽象类的具体作用
    • 4、抽象类实例
  • 二、接口
    • (一)、接口的概念
      • 1、接口与类的区别
      • 2、接口特性
      • 3、抽象类和接口的区别
    • (二)、接口间的继承
      • 1、接口的单继承
      • 2、接口的多继承
    • (三)、接口的实例
    • (四)、标记接口
  • 三、抽象类和接口的使用

抽象类与接口是 java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力。他们两者之间对抽象概念的支持有很大的相似,甚至可以互换,但是也有区别。

一、抽象类

1、抽象类的概念

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

接口设计的好处,牢记多态的好处:让程序猿忘记类型。有了接口以后,类的使用者就不必关心具体类型,而只关注某个类是否具备某种能力。

抽象类的定义格式

抽象类的定义格式:在 class 前添加 abstract(中文意思:抽象的)关键字,就定义了一个抽象类。

abstract class A{}

2、抽象类的注意点

抽象类需要注意:

1、抽象类主要用于被继承,被继承后子类里面需要重写父类(抽象类)里面的所有抽象方法

2、抽象类里面的方法可以有抽象方法和普通成员方法。换句话说也就是有抽象类不一定有抽象方法,但是有抽象方法一定要有抽象类。

3、抽象类不能实例化对象

4、抽象类里面可以有普通成员变量和普通成员方法

5、抽象类可以有构造方法,创立子类对象时候,由子类构造方法初始化父类成员变量

6、抽象类里面的抽象方法没有具体实现,就等于只是放了个名字在抽象类里面,该抽象方法用于被子类重写后通过抽象类这个父类调用子类重写后的方法。

7、如果一个抽象类A继承另一个抽象类B,那么此时这个抽象类A可以不重写B当中的抽象方法。

8、抽象方法不能是private的、static的、final的

eg:

(1)抽象方法不能是private的

abstract class Fruit{abstract private void grow();
}//编译出错:
Error:(4,27)java:非法的修饰组合:abstractprivate

注意:抽象方法没有加访问限定符时,默认是public

(2)抽象方法不能被 final 和 static 修饰,因为抽象方法要被子类重写

public abstract class Shape{abstract final void methodA();abstract public static void methodB();
}//编译报错
//Error:(20,25)java:非法的修饰符组合:abstract和final
//Error:(21,35)java:非法的修饰符组合:abstract和static

抽象方法的介绍

  • 当子类继承父类时候,需要重写父类中的抽象方法,否则会报错。除非子类也是抽象类,继承的父类也是抽象类的时候不用重写父类的抽象方法

此时重写父类抽象方法不报错:

在这里插入图片描述

此时子类是抽象类继承父类也是抽象类的时候,不重写父类的抽象方法不报错:

在这里插入图片描述

3、抽象类的具体作用

  • 那么抽象类的具体作用是什么呢?

便于检查是否错误调用父类方法。因为在写代码的时候,如果用了继承,然后父类是普通类,子类重写了父类方法,然后实例化对象的时候调用的是父类的方法而不是子类重写的方法,此时执行父类的方法得到并不是我们想要的功能。但是如果父类是抽象类,我们在父类中的抽象类可以不用写内容,这样在执行的时候我们可以发现我们调用的方法并没有效果,此时可以发现是错误地使用了父类的方法。

其实抽象类在我看来可以说是便于我们检查我们写代码的时候的错误

4、抽象类实例

在 Java 语言中使用 abstract class 来定义抽象类。如下实例:

/* 文件名 : Employee.java */
public abstract class Employee
{private String name;private String address;private int number;public Employee(String name, String address, int number){System.out.println("Constructing an Employee");this.name = name;this.address = address;this.number = number;}public double computePay(){System.out.println("Inside Employee computePay");return 0.0;}public void mailCheck(){System.out.println("Mailing a check to " + this.name+ " " + this.address);}public String toString(){return name + " " + address + " " + number;}public String getName(){return name;}public String getAddress(){return address;}public void setAddress(String newAddress){address = newAddress;}public int getNumber(){return number;}
}

注意到该 Employee 类没有什么不同,尽管该类是抽象类,但是它仍然有 3 个成员变量,7 个成员方法和 1 个构造方法。 现在如果你尝试如下的例子:


/* 文件名 : AbstractDemo.java */
public class AbstractDemo
{public static void main(String [] args){/* 以下是不允许的,会引发错误 */Employee e = new Employee("George W.", "Houston, TX", 43);System.out.println("\n Call mailCheck using Employee reference--");e.mailCheck();}
}

当你尝试编译 AbstractDemo 类时,会产生如下错误:

Employee.java:46: Employee is abstract; cannot be instantiatedEmployee e = new Employee("George W.", "Houston, TX", 43);^
1 error
  • 继承抽象类

我们可以通过以下方式继承 Employee 类的属性:


/* 文件名 : Salary.java */
public class Salary extends Employee
{private double salary; //Annual salarypublic Salary(String name, String address, int number, doublesalary){super(name, address, number);setSalary(salary);}public void mailCheck(){System.out.println("Within mailCheck of Salary class ");System.out.println("Mailing check to " + getName()+ " with salary " + salary);}public double getSalary(){return salary;}public void setSalary(double newSalary){if(newSalary >= 0.0){salary = newSalary;}}public double computePay(){System.out.println("Computing salary pay for " + getName());return salary/52;}
}

尽管我们不能实例化一个 Employee 类的对象,但是如果我们实例化一个 Salary 类对象,该对象将从 Employee 类继承 7 个成员方法,且通过该方法可以设置或获取三个成员变量。

/* 文件名 : AbstractDemo.java */
public class AbstractDemo
{public static void main(String [] args){Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);System.out.println("Call mailCheck using Salary reference --");s.mailCheck();System.out.println("\n Call mailCheck using Employee reference--");e.mailCheck();}
}

以上程序编译运行结果如下:

Constructing an Employee
Constructing an Employee
Call mailCheck using  Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.
  创建抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样使用他们.抽象类还是有用的重构器,因为它们使我们可以很容易地将公共方法沿着继承层次结构向上移动。(From:Think in java )

二、接口

(一)、接口的概念

接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。在 java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

定一个接口的形式如下:

[public] interface InterfaceName {}

要让一个类遵循某组特地的接口需要使用 implements 关键字,具体格式如下:

class ClassName implements Interface1,Interface2,[....]{
}

1、接口与类的区别

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。
  • 接口不能包含成员变量,除了 static 和 final 变量。
  • 接口不是被类继承了,而是要被类实现。
  • 接口支持多继承。

2、接口特性

  1. 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。

  2. 重写接口中方法时,不能使用 default 访问权限修饰。

public interface USB{void openDevice();  //默认是public的void closeDevice(); //默认是public的
}public class Mouse implements USB{@Overridevoid openDevice(){System.out.println("打开鼠标");}
}//编译报错,重写USB中openDevice方法时,不能使用默认修饰符
//正在尝试分配更低的访问权限;以前为public

注:jdk8中:接口可以包含default方法。

  1. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
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. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。

  2. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

  3. 如果类没有实现接口中的所有抽象方法,则类必须设置为抽象类。

  4. 阿里编码规范中约定,接口中的方法和属性不要加任何修饰符号,保持代码的简洁性。

public interface Flyable{
//接口方法public abstract void mathod1();//public abstract 是固定搭配,可以不写public void method2();abstract void method3();void method4();//注意:在接口中上述写法都是抽象方法,更推荐最后一种,代码更简洁
}

3、抽象类和接口的区别

  1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

注:JDK 1.8 以后,接口里可以有静态方法和方法体了。
注:JDK 1.8 以后,接口允许包含具体实现的方法,该方法称为"默认方法",默认方法使用 default 关键字修饰。更多内容可参考 Java 8 默认方法。
注:JDK 1.9 以后,允许将方法定义为 private,使得某些复用的代码不会把方法暴露出去。更多内容可参考 Java 9 私有接口方法。

  1. 类继承类用extends,类继承接口用implement,接口与接口的继承用extends。

  2. 在普通的类继承抽象类的时候,普通类必须重写抽象类中所有抽象方法,在接口中,继承接口也必须重写接口所有的抽象方法,除非子类是抽象类。

(二)、接口间的继承

一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用 extends关键字,子接口继承父接口的方法。

1、接口的单继承

下面的Sports接口被Hockey和Football接口继承:

// 文件名: Sports.java
public interface Sports
{public void setHomeTeam(String name);public void setVisitingTeam(String name);
}// 文件名: Football.java
public interface Football extends Sports
{public void homeTeamScored(int points);public void visitingTeamScored(int points);public void endOfQuarter(int quarter);
}// 文件名: Hockey.java
public interface Hockey extends Sports
{public void homeGoalScored();public void visitingGoalScored();public void endOfPeriod(int period);public void overtimePeriod(int ot);
}

Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。

相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。

2、接口的多继承

提示:IDEA 中使用 ctrl+i 快速实现接口

在Java中,类的多继承是不合法,但接口允许多继承。在接口的多继承中 extends 关键字只需要使用一次,在其后跟着继承接口。 如下所示:

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

(三)、接口的实例

接口不能直接使用,必须需要有一个“实现类”来实现该接口,实现接口中所有的抽象方法。

public class 类名 implements 接口名称{//.....
}请实现笔记本电脑使用USB鼠标、USB键盘的例子
1.USB接口:包含打开设备,关闭设备功能
2.笔记本类:包含开机功能、关机功能、使用USB设备功能
3.鼠标类:使用USB接口,并具备点击功能
4.键盘类:使用USB接口,并具备输入功能//USB接口
public interface USB {void openDevice();void closeDevice();
}//鼠标类,实现USB接口
public class Mouse implements USB{@Overridepublic void openDevice(){System.out.println("打开鼠标");}@Overridepublic void closeDevice(){System.out.println("关闭鼠标");}public void click(){System.out.println("鼠标点击");}
}//键盘类,实现USB接口
public class KeyBoard implements USB{@Overridepublic void openDevice(){System.out.println("打开键盘");}@Overridepublic void closeDevice(){System.out.println("关闭键盘");}public void inPut(){System.out.println("键盘输入");}
}//笔记本类:使用USB设备
public class Computer {public void powerOn(){System.out.println("打开笔记本电脑");}public void powerOff(){System.out.println("关闭笔记本电脑");}public void useDevice(USB usb){usb.openDevice();if(usb instanceof Mouse){Mouse mouse = (Mouse)usb;mouse.click();}else if(usb instanceof KeyBoard){KeyBoard keyBoard = (KeyBoard) usb;keyBoard.inPut();}usb.closeDevice();}
}//测试类
public class TestUSB {public static void main(String[] args) {Computer computer = new Computer();computer.powerOn();//使用鼠标设备computer.useDevice(new Mouse());//使用键盘设备computer.useDevice(new KeyBoard());computer.powerOff();}
}

(四)、标记接口

最常用的继承接口是没有包含任何方法的接口。

标记接口是没有任何方法和属性的接口。它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。

标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。

例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义如下:

package java.util;
public interface EventListener
{}

没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的:

  1. 建立一个公共的父接口:

    正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener 接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。

  2. 向一个类添加数据类型:

    这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。

三、抽象类和接口的使用

(1)当你关注一个事物的本质时,使用抽象类;当你关注一组操作的时候,使用接口。

(2)如果拥有一些方法并且想让他们中有一些默认的是实现,那么可以使用抽象类。

(3)如果想实现多重继承,那必须使用接口。由于Java不支持多继承,子类不能够继承多类,但是可以实现多个接口。

(4)如果基本功能在不断改变,那么就需要使用抽象类,如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

参考博客:https://blog.csdn.net/SPMAX/article/details/124400507

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何实现云原生?推荐的几个实用工具

云原生是一种软件开发和部署的方法,它依赖于容器、微服务和自动化运维。它能使应用更高效、可靠和可扩展,并适用于不同的云平台。 如果要更直接、更通俗地解释上述概念的话。 云的本源更准确地说是一种文化,一种潮流,它必然是云…

此网站可能不支持TLS1.2协议

问题描述 火狐浏览器版本:“97.0.1 (64 位)”,打开360网神设备Web管理地址时出现:“此网站可能不支持TLS1.2协议,而这是Firefox支持的最低版本。”,如下图所示。 原本是默认使用https协议打开的,看起来出问…

蓝桥杯每日一题:不同路径数(dfs深度优先)

给定一个 nm的二维矩阵,其中的每个元素都是一个 [1,9] 之间的正整数。 从矩阵中的任意位置出发,每次可以沿上下左右四个方向前进一步,走过的位置可以重复走。 走了 k 次后,经过的元素会构成一个 (k1) 位数。 请求出一共可以走出…

零基础机器学习做游戏辅助第十五课--原神自动钓鱼(五)完整效果

一、先上效果二、整理思路我们现在已经具备了所有需要的技术,我们梳理出所有技术的流程。判断当前钓鱼状态(未抛竿、已抛竿、上鱼中)。未抛竿,截图并识别图中所有鱼类,选择其中一个种类。根据以选择鱼类选择对应鱼饵。…

从一个实例配置引入Prometheus的PromQL语法

1. PromQL介绍 PromQL提供对时间序列数据进行逻辑运算、过滤、聚合的支持。应用于数据查询、可视化、告警处理 2. 基本用法 2.1 查询时间序列 点击Prometheus图标,进行查询页面。可以点击地图图标查看有哪些metrics name。输入要查询的metrics name和过滤条件,然后点击执行…

2023年功能测试还值得入行吗?

前言 鉴于笔者从13年入行IT行业,经历了只有开发没有测试的阶段,经历了14年只要会基本的功能测试在一线就能薪资过万的阶段,经历了17年只要会一点自动化,会一点性能就能蒙骗过面试官的阶段,更经历了19年所有面试官对于…

基于大规模边缘计算的千万级聊天室技术实践

当前直播成为一种流行趋势,带货直播,网红带货,明星在线演唱会等,进一步使得直播聊天室变成了一个当前必备的能力,面向大型,超大型的直播场景,技术上也在不断的进行迭代更新。 大规模边缘聊天室如…

如何或者无插件Web页面监控播放软件LiveNVR的固定视频流地址,实现大屏上墙、播放、视频分析等目的

1、LiveNVR介绍 LiveNVR的安防监控的视频直播,可以按标准的Onvif/RTSP协议接入监控设备,也可以通过海康、大华、天地伟业等厂家私有SDK接入监控,实现web页面的播放和录像回放。 可以分发HTTP-FLV、WS-FLV、WebRTC、RTMP、HLS(M3U8)、RTSP等多…

全球化趋势下,如何建设稳定高效的技术能力?

如果将全球化比作一场航行,每个期望走出去的企业都是水手,那么是造一艘属于自己的船,还是搭乘已有的船呢?在不同的时间和场景下,相信每个水手都有自己的答案。 近几年,在国际政经环境复杂变幻的形势之下&am…

ImportError: Can not find the shared library: libhdfs3.so解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…

活动回顾|中文社区面对面·上海站

回顾来了! 「中文社区面对面」首次线下交流活动,于 2 月 26 日下午在上海德必世纪 WE 成功举办,迎来了 30 位上海小伙伴的热情参与!Jina AI 高级算法工程师王峰博士与大家分享 Jina AI 的“三驾马车”,百万粉丝B站效率…

4.文件管理

文章目录1、初识文件管理1.1、回顾1.2、文件的属性1.3、无结构文件/有结构文件1.4、文件之间应该怎样组织起来?1.5、操作系统应该向上提供哪些功能?1.6、从上往下看,文件应如何存放在外存?1.7、其他需要由操作系统实现的文件管理功…

【蓝桥杯嵌入式】点亮LED灯,流水灯的原理图解析与代码实现——STM32

🎊【蓝桥杯嵌入式】专题正在持续更新中,原理图解析✨,各模块分析✨以及历年真题讲解✨都在这儿哦,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 - 蓝…

实践数据湖iceberg 第四十二课(业界视野)业界的流批一体架构

系列文章目录 实践数据湖iceberg 第一课 入门 实践数据湖iceberg 第二课 iceberg基于hadoop的底层数据格式 实践数据湖iceberg 第三课 在sqlclient中,以sql方式从kafka读数据到iceberg 实践数据湖iceberg 第四课 在sqlclient中,以sql方式从kafka读数据到…

React(三):脚手架、组件化、生命周期、父子组件通信、插槽、Context

React(三)一、脚手架安装和创建1.安装脚手架2.创建脚手架3.看看脚手架目录4.运行脚手架二、脚手架下从0开始写代码三、组件化1.类组件2.函数组件四、React的生命周期1.认识生命周期2.图解生命周期(1)Constructor(2&…

【封装xib补充 Objective-C语言】

一、那么首先,咱们就从这个结果来分析 1.就不给大家一步一步分析了,直接分析我们这里怎么想的, 首先,我们看到这样的一个界面,我们想,这些应用数据是不是来源于一个plist文件吧, 所以说,我们首先要,第一步,要懒加载,把这个plist文件中的数据,加载起来, 那么,因…

「JVM 高效并发」锁优化

为了线程间更高效的共享数据及解决竞争问题,提高程序执行效率,JDK 6 做了大量锁优化,如适应性自旋(Adaptive Spinning)、锁消除(Lock Elimination)、锁膨胀(Lock Coarsening&#xf…

机器学习知识总结 —— 21. 什么是主成分分析

文章目录什么是PCA(Principal Component Analysis)协方差矩阵什么是协方差协方差矩阵特征值与特征向量PCA降维什么是PCA(Principal Component Analysis) 在机器学习中,PCA(Principal Component Analysis&a…

实践数据湖iceberg 第四十一课 iceberg的实时性-业界的checkpoint配置

系列文章目录 实践数据湖iceberg 第一课 入门 实践数据湖iceberg 第二课 iceberg基于hadoop的底层数据格式 实践数据湖iceberg 第三课 在sqlclient中,以sql方式从kafka读数据到iceberg 实践数据湖iceberg 第四课 在sqlclient中,以sql方式从kafka读数据到…

【python学习笔记】:中文编码

Python 中文编码 我们已经学会了如何用 Python 输出 "Hello, World!",英文没有问题,但是如果你输出中文字符 "你好,世界" 就有可能会碰到中文编码问题。 Python 文件中如果未指定编码,在执行过程会出现报错…