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

news2025/2/28 17:38:10

【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 instantiated
      Employee e = new Employee("George W.", "Houston, TX", 43);
                   ^
1 error
  • 继承抽象类

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


/* 文件名 : Salary.java */
public class Salary extends Employee
{
   private double salary; //Annual salary
   public Salary(String name, String address, int number, double
      salary)
   {
       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.0

Call 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{
    @Override
    void 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{
   @Override
    public void openDevice(){
       System.out.println("打开鼠标");
   }
 
   @Override
    public void closeDevice(){
       System.out.println("关闭鼠标");
   }
 
   public void click(){
       System.out.println("鼠标点击");
   }
}
 
//键盘类,实现USB接口
public class KeyBoard implements USB{
    @Override
    public void openDevice(){
        System.out.println("打开键盘");
    }
 
    @Override
    public 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.coloradmin.cn/o/379567.html

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

相关文章

MyBatis 查出数据不一致 MyBatis返回数据和数据库查询不一致

MyBatis 查出数据不一致 MyBatis返回数据和数据库查询不一致 --- MyBatis查询到的数据 和 Sql 查询到的数据不一致 一、背景 近期工作中,遇到一个MyBatis查询数据不一致的问题,表现是: sql在数据库中查询出10条数据,mybatis 返回的…

【服务器数据恢复】VSAN数据迁移中断导致容量盘故障的数据恢复案例

VSAN简介: VSAN是以vSphere内核为基础开发,可以扩展使用的分布式存储架构。该架构在vSphere集群主机中安硬盘及闪存构建VSAN存储层,通过存储进行管理与控制,最终形成一个共享存储层。 VSAN数据存储是一个对象存储,以文…

MySQL事务的12连问

事务的12连问,相信大家看完肯定会有帮助的。 1. 什么是数据库事务? 事务,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。 假如A转账给B 100 元,先从A的…

windows@系统环境变量备份@注册表操作@reg命令行操作注册表

文章目录备份注册表🎈备份环境变量powershell函数从注册表文件还原命令行操作注册表更新某个key备份注册表🎈 完整的注册表备份可能达到500MB打开register editor 命令行里可以输入regedit.exe打开 可以局部备份 备份环境变量powershell函数 function …

JavaEE进阶第五课:SpringBoot的创建和使用

上篇文章介绍了Bean 作用域和生命周期,这篇文章我们将会介绍SpringBoot的创建和使用 目录1.为什么要学习StringBoot1.1什么是SpringBoot1.2SpringBoot的优点2.如何用Idea创建SpringBoot项目3.项目目录介绍和运行3.1输入Helloworld结尾1.为什么要学习StringBoot 在前…

Python 算法交易实验49 Step1 DataETL

说明 万丈高楼平地起 按照前面的规划,开始有序推进我的【15% 资金加速器】计划。这一步是通过某个源,获取分钟级数据,然后送到第一个ADBS。 Sniffer : 读取数据并发送到入队列。一开始我会把文件以离线形式上传到某个folder,所以…

VMware16安装MacOS【详细教程】

安装VMware workstation 双击安装包,然后一直下一步就行了。 进行VMware安装,一直 下一步 在输入产品密钥这一步,如果有查找到可用密钥就填进去,没有就跳过,进入软件后也能输入密钥的。 输入密钥。 最后一步&#xff…

MyBatis——进阶操作

resultMap xml中可以通过returnType来指定返回的对象,只需要一个对象名就可以返回所有的属性 但是,如果sql中的属性名和对象的名称不一致,那么就需要resultMap来指定返回的数据了 当数据库中是username,而对象是name时&#xf…

zabbix主机发现、zabbix下的API、服务的监控部署

文章目录前言一、zabbix主机发现1.手动添加2.自动发现3.自动注册二、zabbix api1.获取token2.使用api检索主机3.通过api删除主机4.使用api添加主机5.纯代码过程三、服务监控1.nginx监控2.mysql监控(1)zabbix自带mysql模板(2)perco…

大数据技术之Maxwell基础知识

大数据技术之Maxwell基础知识 文章目录大数据技术之Maxwell基础知识0、写在前面1、Maxwell 概述1.1 Maxwell 定义1.2 Maxwell 工作原理1.2.1 MySQL 主从复制过程1.2.2 Maxwell 的工作原理1.2.3 MySQL 的 binlog1.3 Maxwell与Cannal对比2. Maxwell 使用2.1 Maxwell 安装部署2.1.…

Semaphore类原理剖析

1.什么是Semaphore Semaphore也是Java中的同步器,与CountDownLatch和CyclicBarrier不同的是,他的内部计数器是递增的。在一开始我们不需要知道有多少个需要同步的线程,只需要在需要同步的地方调用acquire方法指定需要同步的线程个数。 2.Se…

【C语言】结构体进阶

一、结构体 1. 结构体的声明 (1) 结构的基础知识 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。(2)结构的声明 struct tag {member-list; }variable-list;例如描述一个学生&#x…

「需求分析」业务架构师需求分析技术权威指南

需求分析,也称为需求工程,是定义用户对正在构建或修改的新软件的期望的过程。在软件工程中,它有时被一些松散的名称所引用,例如需求收集或需求捕获。需求分析包括那些为一个新的或改变的产品或项目确定需要或满足的条件的任务&…

进程内存空间

我们直接用linux演示 我们将这个代码编译成目标文件&#xff0c;然后查看内容 #include <stdlib.h> #include <pthread.h> int sum(int x,int y) {return xy; }int main(){sum(2,3);return 0; }编译 我们反汇编这个目标文件 我们发现这些汇编代码不好阅读&#…

有趣的HTML实例(十五) 注册登录界面(css+js)

我并不是每次吃完饭就看电视&#xff0c;有时我边吃边看电视&#xff0c;生活中有些改变会增加乐趣。 ——《加菲猫》 目录 一、前言 二、往期作品回顾 三、作品介绍 四、本期代码介绍 五、效果显示 六、编码实现 index.html style.css script.js 七、获取源码 公众…

何为数据分析?数据分析流程是啥?

一、什么是数据分析 指用专业的统计分析方法对大量数据进行分析&#xff0c;并加以详细研究和概括总结&#xff0c;提取有价值的信息&#xff0c;形成有效的分析结论&#xff0c;从而影响业务决策 二、数据分析的重要性 一切事物&#xff0c;如果不能量化它&#xff0c;我们…

Allegro如何手动让静态铜皮避让过孔操作指导

Allegro如何手动让静态铜皮避让过孔操作指导 在用Allegro做PCB设计的时候,如果铺的是静态铜皮,铜皮铺在过孔上会造成短路,需要手动避让下,如下图 下面介绍如何手动避让,具体操作如下 点击Shape点击Manual Void/Cavity

itop-3568开发板驱动学习笔记(3) 字符设备(上)

《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记 文章目录字符设备简介申请字符设备号注册字符设备创建设备节点字符设备驱动框架&#xff08;实验&#xff09;杂项设备字符设备简介 字符设备是指在I/O传输过程中以字符为单位进行传输的设备&#xff0c;例如键盘&am…

如何使用ApacheTomcatScanner扫描Apache Tomcat服务器漏洞

关于ApacheTomcatScanner ApacheTomcatScanner是一个功能强大的Python脚本&#xff0c;该脚本主要针对Apache Tomcat服务器安全而设计&#xff0c;可以帮助广大研究人员轻松扫描和检测Apache Tomcat服务器中的安全漏洞。 功能介绍 1、支持使用多线程Worker搜索Apache Tomcat服…

ARM简介及其发展历史

前言ARM名声很大&#xff0c;最近在学习STM32&#xff0c;也借机梳理一下关于ARM的各种概念和信息。 本文主要内容&#xff1a;ARM一词的含义&#xff0c;ARM的发展历史&#xff0c;ARM cortex系列处理器简介与ARM在不同市场的应用情况。 一. ARM一词的4种含义1.1 ARM公司 AR…