【Java】接口详解

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

一个简单的接口代码示例

interface IShape {
void draw();
}
class Cycle implements IShape {
@Override
public void draw() {
System.out.println("○");
}
}
public class Data {
public static void main(String[] args) {
IShape shape = new Rect();
shape.draw();
}
}

定义接口的注意事项:

  • 使用 interface 定义一个接口
  • 接口中的方法一定是抽象方法, 因此可以省略 abstract
  • 接口中的方法一定是 public, 因此可以省略 public
  • Cycle 使用 implements 继承接口. 此时表达的含义不再是 "扩展", 而是 "实现"
  • 在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例.
  • 接口不能单独被实例化

定义一个完整的接口是这样的:

interface Ishape{

        public static final int num = 10;

        public abstruct void draw();

}

 但是严格来说我们在定义一个接口的时候通常会省略  public static final 和 public abstruct ,在我们定义接口的时候里面的变量和方法会自动加上。

省略之后的写法:

interface Ishape{

         int num = 10;

         void draw();

}

实现多个接口

 有的时候我们需要让一个类同时继承自多个父类. 这件事情在有些编程语言通过 多继承 的方式来实现的.然而 Java 中只支持单继承, 一个类只能 extends 一个父类. 但是可以同时实现多个接口, 也能达到多继承类似的效果。

代码示例:

interface Ifly{
    void fly();
}
interface Irunning{
    void running();
}
interface Iswimming{
    void swimming();
}
abstract class Animal{
    public String name;
    public int age;
    public Animal(String name,int age){
        this.name = name;
        this.age = age;
    }
    abstract public void eat();
}
class Dog extends Animal implements Iswimming , Irunning{

    public Dog(String name,int age){
        super(name,age);
    }

    @Override
    public void running() {
        System.out.println(this.name + "正在跑");
    }

    @Override
    public void swimming() {
        System.out.println(this.name + "正在游泳");
    }

    @Override
    public void eat() {
        System.out.println(this.name + "正在吃狗粮");
    }
}

public class Data{
    public static void test1(Animal animal){
        animal.eat();
    }
    public static void test2(Ifly ifly){
        ifly.fly();
    }
    public static void test3(Iswimming iswimming){
        iswimming.swimming();
    }
    public static void test4(Irunning irunning){
        irunning.running();
    }

    public static void main(String[] args) {
        test1(new Dog("小黄" ,20));
        test3(new Dog("小黄" ,20));
        test4(new Dog("小黄" ,20));
    }
}

上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口。

在这个代码中我们定义了三个接口:Ifly 、Irunning 、Iswimming 。一个抽象类:Animal 。然后定义了一个类来继承这个抽象类并且实现了两个接口。

上述代码运行结果:

接口的常见使用案例

Comparable接口

 给对象数组排序

代码示例:

class Student implements Comparable<Student>{
    private String name;
    private int score;
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    @Override
    public String toString() {
        return "[" + this.name + ":" + this.score + "]";
    }

    @Override
    public int compareTo(Student o) {
        return this.score - o.score;
    }
}
public class Data{
    public static void main(String[] args) {
        Student[] student = {
                new Student("小明",87),
                new Student("小黄",94),
                new Student("小李",89)};
        Arrays.sort(student);
        System.out.println(Arrays.toString(student));
    }
}

在这个代码中我们定义了一个 Student 类:

class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
}

 然后用这个类创建了一个数组:

Student[] student = {
        new Student("小明",87),
        new Student("小黄",94),
        new Student("小李",89)};

接着我们给 Student 类实现接口 Comparable<Student> ,这样我们就可以给该类实例化的成员进行比较大小。

上述代码的运行结果:

 注意事项: 对于 sort 方法来说, 需要传入的数组的每个对象都是 "可比较" 的, 需要具备 compareTo 这样的能力. 通过重写 compareTo 方法的方式, 就可以定义比较规则。

Comparator接口

另外一种比较一个类的两个实例的方法:

代码示例:

class Person implements Comparable<Person>{
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Person o) {
        return this.age - o.age;
    }
}
class AgeComparator implements Comparator<Person>{

    @Override
    public int compare(Person o1, Person o2) {
        return o1.age - o2.age;
    }
}
class NameComparator implements Comparator<Person>{

    @Override
    public int compare(Person o1, Person o2) {
        return o1.name.compareTo(o2.name);
    }
}
public class Data{
    public static void main(String[] args) {
        Person p1 = new Person("小明",20);
        Person p2 = new Person("小黄",30);
        System.out.println(p1.compareTo(p2));
        AgeComparator agecomparator = new AgeComparator();
        System.out.println(agecomparator.compare(p1,p2));
        NameComparator namecomparator = new NameComparator();
        namecomparator.compare(p1,p2);
    }
}

在这个代码中我们为了进行比较,额外创建了一个类来实现 Comparator 接口并且在该类里面重写 compare 方法。

Clonable 接口

浅拷贝 VS 深拷贝

浅拷贝示例

代码示例:

class Person implements Cloneable{
    public int age;
    public Person(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Data{
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person(20);
        Person p2 = (Person)p1.clone();
        System.out.println(p1);
        System.out.println(p2);
    }
}

这里我们定义了一个类 Person 并且实现了接口 Cloneable 重写了方法 clone 。在测试类中我们将 p1 里面的内容拷贝到了 p2 里面。

代码运行结果:

接着我们再定义一个 Money 类:

class Money{
    public double money = 19.9;
}

并且在 Person 类中使用这个类:

 

class Person implements Cloneable{
    public int age;
    public Money m = new Money();
    public Person(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

 接着我们再进行拷贝,将 p1 里面的内容拷贝到 p2 里面,然后我们改变 p2 里面的内容,并且将其输出:

很快我们就能看出一个问题:改变 p2 里面的内容,而 p1 里面的内容也跟着改变了呢?

接着我们引入深拷贝的理念:

深拷贝示例

代码示例:

class Money implements Cloneable{
    public double money = 19.9;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Person implements Cloneable{
    public int age;
    public Money m = new Money();
    public Person(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person)super.clone();
        tmp.m = (Money)this.m.clone();
        return tmp;
    }
}
public class Data{
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person(20);
        Person p2 = (Person)p1.clone();
        System.out.println(p1.m.money);
        System.out.println(p2.m.money);
        p2.m.money = 99.9;
        System.out.println(p1.m.money);
        System.out.println(p2.m.money);
    }
}

运行结果:

我们发现我们刚刚提出的问题被解决了。

这里我们改变了两个地方:

1、 将 Money 类也实现 Clonable 接口重写 clone 方法,将其具备能被拷贝的能力。

class Money implements Cloneable{
    public double money = 19.9;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

2、重写 Person 类里面的 clone 方法。

 

protected Object clone() throws CloneNotSupportedException {
    Person tmp = (Person)super.clone();
    tmp.m = (Money)this.m.clone();
    return tmp;
}

接口间的继承

接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字。

interface IRunning {
    void run();
}
interface ISwimming {
    void swim();
}
interface IAmphibious extends IRunning, ISwimming {
    void eat();
}

接口间的继承相当于把多个接口合并在一起。这里我们定义接口 Iamphibious 来继承了接口 IRunning 和接口 ISwimming 。这样该接口就有了另外两个接口里面的抽象方法,并且该接口也可以定义另外的抽象方法。

总结

抽象类与接口的区别:

核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法。

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

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

相关文章

如何制作一本温馨的电子相册呢?

随着科技的不断发展&#xff0c;电子相册已经成为了一种流行的方式来记录和分享我们的生活。一张张照片&#xff0c;一段段视频&#xff0c;都能让我们回忆起那些温馨的时光。那么&#xff0c;如何制作一本温馨的电子相册呢&#xff1f; 首先&#xff0c;选择一款合适的电子相册…

绕过WAF(Web应用程序防火墙)--介绍、主要功能、部署模式、分类及注入绕过方式等

网站WAF是一款集网站内容安全防护、网站资源保护及网站流量保护功能为一体的服务器工具。功能涵盖了网马/木马扫描、防SQL注入、防盗链、防CC攻击、网站流量实时监控、网站CPU监控、下载线程保护、IP黑白名单管理、网页防篡改功能等模块。能够为用户提供实时的网站安全防护&…

Docker无法stop或者rm指定容器

Docker无法stop或者rm指定容器 今日准备重启一下docker 容器部署的 Nginx 时&#xff0c;使用的命令是 docker exec -it ir-nginx nginx -s reload 结果发现无法重启报错 然后想着关闭再启动&#xff0c;结果发现 docker restart 、docker stop 、docker kill 、docker exec 都…

STM32-15-DMA

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 STM32-13-MPU STM32-14-FSMC_LCD 文章目录 STM…

基础—SQL—DQL(数据查询语言)条件查询

一、DQL—语法 SELECT 字段列表 FROM 表名 WHERE 条件列表; 注意&#xff1a;条件列表可以是一个&#xff0c;也可以是多个。 二、条件列表的一些构建形式 注意&#xff1a; 1、BETWEEN ... AND ... &#xff08;between 后面跟最小值&#xff0c;and 后面跟最大值&#xff0…

VxWorks PCI驱动

1 概述 PCI接口是一种DMA接口&#xff0c;通过DMA接口&#xff0c;CPU和外设能够进行内存的共享&#xff0c;这样CPU访问外设时只需要访问计算机系统的内存就可以了&#xff0c;这样做的一个重要的目的就是增加外部设备的自主性&#xff0c;在外部设备工作时可以不需要CPU的参与…

《QT从基础到进阶·四十一》无法解析的外部符号及生成事件加入QT打包命令报错问题

其他无法解析的外部符号&#xff1a; 无法解析的外部符号 "public: virtual struct QMetaObject const * __cdecl ML_AddinManger::metaObject(void)const "… 无法解析的外部符号 “public: virtual void * __cdecl ML_AddinManger::qt_metacast(char const *)” (?…

DynamiCrafter ComfyUI 教程 | 对图片转视频的效果进行精细化控制

近日&#xff0c;由北大、腾讯AI Lab联合推出的 AI 视频生成工具 DynamiCrafter 一经上线便引起了巨大反响。只需要输入一张普普通通的静态图&#xff0c;加上几句简单的文字引导&#xff0c;瞬间就能生成超逼真的动态视频&#xff0c;简直不要太厉害&#xff01; 静态图 fire…

数据结构汇总

等同于&#xff1a; 旋转的时候忽略Nil,选装完再加上。

小华半导体MCU方案选型和应用

小华半导体有限公司是中国电子信息产业集团有限公司旗下集成电路业务平台华大半导体有限公司的核心子公司&#xff0c;目前团队规模约300人&#xff0c;其中75%以上为研发人员&#xff0c;国内细分行业规模最大&#xff0c;核心骨干拥有国际MCU大厂25年以上从业经验。 小华半导…

风险投资公司正在帮助小投资者购买Anthropic、OpenAI等热门公司的股票

近年来&#xff0c;风险投资公司对于人工智能&#xff08;AI&#xff09;领域的公司&#xff0c;如Anthropic、Groq、OpenAI等&#xff0c;表现出了极高的投资热情。这些公司因为它们在AI技术方面的创新而备受瞩目。但是&#xff0c;对于很多小投资者来说&#xff0c;由于资金有…

vmware将物理机|虚拟机转化为vmware虚机

有时&#xff0c;我们需要从不同的云平台迁移虚拟机、上下云、或者需要将不再受支持的老旧的物理服务器转化为虚拟机&#xff0c;这时&#xff0c;我们可以用一款虚拟机转化工具&#xff1a;vmware vcenter converter standalone&#xff0c;我用的是6.6的版本&#xff0c;当然…

心缘Hub小程序

心缘Hub小程序 文章目录 心缘Hub小程序[TOC](文章目录) 前言飞书文章&#xff1a;[添加链接描述](https://mqdyd6qj756.feishu.cn/wiki/X9qbwrq70i43W0kr5X8cqytSnKb) 一、简介 前言 飞书文章&#xff1a;添加链接描述 一、简介 心缘Hub 不要钱可以匹配 有缘人 、直接拿微信…

python无限弹窗的代码

一个简单的Python代码示例&#xff0c;用于在特定的时间间隔内显示一个简单的弹窗。这个代码使用了Python的tkinter库来创建一个简单的GUI窗口。 python import tkinter as tk import time def popup(): popup_window.deiconify() # 显示窗口 popup_window.wait_window() # 等…

QT_UI设计

mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE //命名空间 namespace Ui { class MainWindow; } //ui_MainWindow文件里定义的类&#xff0c;外部声明 QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_O…

keil5常见使用技巧记录(更新)

快速到函数定义 F12或自己定义快捷键CTRLK&#xff08;个人设定&#xff09; 修改快捷键 下图实例是快速跳转到函数或变量定义位置&#xff0c;当然可以定义其他功能快捷键&#xff0c;如快速注释多行&#xff0c;快速消除注释等 标记全部查找变量的蓝色框取消 CTRLshiftF2…

gradle构建项目简单入门

gradleProject 搭建gradle项目步骤 官网文档地址&#xff1a;https://docs.gradle.org/current/userguide/userguide.html Getting Started 1.Gradle核心内容 1.Gradle介绍 Project&#xff1a;类似模块划分Build Scripts&#xff1a;构建ProjectDependency Management&…

2020长安杯

链接成功 检材一 1检材 1 的操作系统版本是 ()A. CentOS release 6.5 (Final)B. Ubuntu 16.04.3 LTSC. Debian GNU/ Linux 7.8 (wheezy)D. CentOS Linux release 7.6.1810 (Core)D 2检材 1 中&#xff0c;操作系统的内核版本是 ()(答案格式&#xff1a; “1.2.34” 数字和半角…

使用正则表达式分割字符串

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 split()方法用于实现根据正则表达式分割字符串&#xff0c;并以列表的形式返回。其作用同字符串对象的split()方法类似&#xff0c;所不同的就是分割…

多校园在校跑腿小程序 代拿快递+寄取快递+外卖配送等 前后端分离带完整的安装代码包以及搭建教程

系统概述 该系统采用前后端分离的开发模式&#xff0c;后端采用稳定的服务器端架构&#xff0c;确保系统稳定、安全、高效地运行。前端则采用轻量级框架&#xff0c;兼容多平台、多设备&#xff0c;确保用户在不同场景下都能获得流畅的使用体验。同时&#xff0c;还提供了完整…