Java基础(十一):抽象类和接口

抽象类和抽象方法

  • 抽象方法
    1.使用abstract修饰的方法,没有方法体,只有声明;
    2.定义的是一种“规范”,就是告诉子类必须给抽象方法提供具体的实现。
  • 抽象类
    包含抽象方法的类的抽象类;
    通过抽象类,我们可以做到严格限制子类的设计,使子类之间更加通用。
package obstractClass;


// 如果类含有抽象方法,类就必须含有abstract
public abstract class Animal {
    int age;
    public abstract void rest();
    public abstract void run();

    public void shout(){
        System.out.println("Animal.shout");
    }
}

// 子类 Dog、Cat类中必须含有抽象父类里的抽象方法,不然报错。
class Dog extends Animal {
    @Override
    public void rest() {
        System.out.println("Dog.rest");
    }

    @Override
    public void run() {
        System.out.println("Dog.run");
    }
}

class Cat extends Animal {

    @Override
    public void rest() {
        System.out.println("Cat.rest");
    }

    @Override
    public void run() {
        System.out.println("Cat.run");
    }
}

抽象类的使用要点:

  1. 有抽象方法的类只能定义成抽象类。
  2. 抽象类不能实例化,即不能用 new 来实例化抽象类。
  3. 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new示例,只能用来被子类调用。
  4. 抽象类只能被继承。
  5. 抽象方法必须被子类实现。

接口(interface)

接口就是一种规范(就像我们人间的法律一样),所以实现类都要遵守。

接口的作用

  • 为什么需要接口?接口和抽象类的区别?
    接口就是比 “抽象类” 还 “抽象” 的 “抽象类”(笑死我了。可以简称 “抽象Plus”),可以更加规范的对子类进行约束。全面地专业的实现:规范和具体的实现分离

接口是两个模块之间通信的标志,通信规范。如果能把你要设计的模块之间的接口定义好,就相当与完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。工作时,做系统时往往就是使用 “面向接口” 的思想来设计系统。

接口和实现类不是父子关系,是实现规则的关系。比如:我定义一个接口 Runnable,Car 实现它就能在地上跑,Train 实现它也能在地上跑,飞机实现它也能在地上跑。就是说如果它是交通工具,就一定能跑,但是一定要实现 Runnable 接口。

如何定义和使用接口

格式生命
[访问修饰符] interface 接口名 [extends 父接口1, 父接口2...] {
  常亮定义;
  方法定义;
}
定义接口的详细说明:
  • 访问修饰符: 只能是 public 或默认。
  • 接口名: 和类名采用相同命名机制。
  • extends: 接口可以多继承。
  • 常量: 接口中的属性只能是常量,总是: public static final 修饰。不写也是。
  • 方法: 接口中的方法只能是:public abstract。省略的话,也是 public abstrac。
package TestInterface;

public interface Volant {
    /*public static final */int Fly_HEIGHT = 100;

    /*public abstract */void fly();
}


interface Honest {
    void helpOther();
}

class BirdMan implements Volant {
    public void fly() {
        System.out.println("I'm fly");
    }
}

class Angle implements Volant, Honest {
    @Override
    public void helpOther() {
        System.out.println("I'm angle");
    }

    @Override
    public void fly() {
        System.out.println("I'm fly");
    }
}

class Plane implements Volant {
    @Override
    public void fly() {
        System.out.println("Plane.fly");
    }
}
// 测试 接口代码
package TestInterface;

import encapsulation.a.Person;

public class Test {
    public static void main(String[] args) {
        // 同时Plane实例拥有接口Volant的约束
        Plane p = new Plane();
        p.fly();

        // 同时Angle实例拥有接口Volant, Honest的约束
        Angle p2 = new Angle();
        p2.fly();
        p2.helpOther();
        System.out.println(Volant.Fly_HEIGHT); // log: 100
    }
}

// AI生成-代码解读:
// 第一段代码定义了几个接口和类:
// 1. Volant接口 - 定义了fly()方法和Fly_HEIGHT常量,表示可以飞行的能力
// 2. Honest接口 - 定义了helpOther()方法
// 3. BirdMan类 - 实现了Volant接口
// 4. Angle类 - 同时实现了Volant和Honest两个接口,既能飞又有爱心
// 5. Plane类 - 实现了Volant接口,可以飞行

// 第二段代码展示了接口的使用:
// 1. 创建Plane对象并调用fly()方法:
// - 通过接口类型Volant约束了Plane对象的行为
// - p.fly()输出"Plane.fly"

// 2. 创建Angle对象并调用两个接口方法:
// - 可以调用Volant接口的fly()方法
// - 也可以调用Honest接口的helpOther()方法
// - 展示了一个类可以实现多个接口

// 3. 访问接口常量:
// - Volant.Fly_HEIGHT直接通过接口名访问常量
// - 说明接口中的常量默认是public static final的
// - 输出常量值100

要点:

  • 子类通过 implements 来实现接口中的规范。
  • 接口不能创建实例,但是可用于声明引用变量类型。
  • 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是 public的。
  • JDK1.8(不含8)之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。
  • JDK1.8(含8)后,接口中包含普通的静态方法、默认方法。

接口中定义静态方法和默认方法

Java8之前,接口中只能定义抽象方法,不能定义静态方法和默认方法。
Java8后,接口中可以定义静态方法和默认方法。

默认方法

   Java8 及以上版本,允许给接口添加一个非抽象的方法实现,只需要使用 default 修饰,这个特征又叫默认方法(也成为扩展方法)

   默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,接口可以提供默认方法的实现,所有这个接口的实现类都可以得到默认方法。

// 定义我们的默认方法
package TestInterface;

public interface TestDefault {
    void printInfo();

    // 利用default关键词定义默认方法
    default  void moren() {
        System.out.println("TestDefault.moren");
        System.out.println("测试默认方法");
    }
}


class TestDefaultImp01 implements TestDefault {
    @Override
    public void printInfo() {
        System.out.println("TestDefaultImp01");
    }
}
package TestInterface;

import encapsulation.a.Person;

public class Test {
    public static void main(String[] args) {
        System.out.println("==============测试我们的默认方法==============");
        TestDefaultImp01 td = new TestDefaultImp01();

        td.printInfo();  // log: TestDefaultImp01

        // log: TestDefault.moren
        // log: 测试默认方法
        td.moren();
    }
}

JDK8 新特性-静态方法

   JAVA8 以后,我们也可以在接口中直接定义静态方法的实现。这个静态方法直接从属于接口(接口也是类,一种特殊的类),可以通过接口名调用。
   如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于了当可以通过子类名直接调用

// 在进口中定义静方法
package TestInterface;

// 测试接口中的新特性(默认方法、静态方法)
public interface TestDefault {
    ...
    public static void testStatic01(){
        System.out.println("TestDefault.testStatic01");
    }
}


class TestDefaultImp01 implements TestDefault {
    ...
    public static void testStatic01(){
        System.out.println("TestDefaultImp01.test");
    }
}
package TestInterface;

public class Test {
    public static void main(String[] args) {
        System.out.println("==============测试我们的静态方法==============");
        TestDefault.testStatic01();  // TestDefault.testStatic01

        // 如果在TestDefaultImp01类里没有写静态方法testStatic01时候,下面这段代码就会报错。
        // td.testStatic01(); // error 子类无法使用接口中的静态方法类

        // 除非在类里添加testStatic01, 但是它和接口里的testStatic01不是从属关系。两者个子属于自己的类/接口。切记
        TestDefaultImp01.testStatic01();  // log: TestDefaultImp01.testt
    }
}

总结

本文主要介绍了Java接口的以下重要知识点:

  1. 接口的基本概念和特性

    • 接口是一种特殊的抽象类
    • 接口中的方法默认都是public abstract的
    • 接口中的属性默认都是public static final的
    • 接口支持多继承
  2. JDK8新特性 - 默认方法

    • 可以使用default关键字在接口中定义默认方法实现
    • 实现类可以直接使用默认方法,也可以重写默认方法
    • 解决接口升级的问题
  3. JDK8新特性 - 静态方法

    • 接口中可以直接定义静态方法
    • 静态方法属于接口本身
    • 实现类不能直接使用接口的静态方法
    • 实现类中的同名静态方法与接口中的静态方法无关

思考题

  1. 接口与抽象类有什么区别?

  2. 为什么Java 8要引入接口默认方法?这个特性主要解决什么问题?

  3. 以下说法正确的是:
    A. 接口中的静态方法可以被实现类继承
    B. 实现类可以直接调用接口的静态方法
    C. 接口的静态方法只能通过接口名调用
    D. 实现类中的同名静态方法会覆盖接口的静态方法

  4. 如果一个类实现了多个接口,这些接口中有相同的默认方法,编译器会如何处理?

  5. 接口是否可以有构造方法?为什么?

答案:

  1. 主要区别:

    • 抽象类可以有构造方法,接口不能有
    • 抽象类可以有普通成员变量,接口只能有常量
    • 抽象类方法可以有不同访问修饰符,接口方法默认public
    • 类只能单继承抽象类,但可以实现多个接口
  2. 引入默认方法主要是为了解决接口升级的问题。当需要在接口中新增方法时,若不提供默认实现,则所有实现类都必须实现新方法,这会导致现有代码不兼容。有了默认方法,就可以在接口中提供向下兼容的实现。

  3. 正确答案是C。接口的静态方法属于接口本身,只能通过接口名调用,不能被实现类继承或直接调用。实现类的同名静态方法是完全独立的方法。

  4. 这种情况下编译器会报错,要求实现类必须重写这个方法来解决冲突。这被称为"钻石问题"。

  5. 接口不能有构造方法。因为接口是一个完全抽象的类型,不能被实例化,所以不需要构造方法。接口中定义的都是抽象行为和常量。

寄语:千里跬步,始于足下。

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

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

相关文章

进程间通讯

简介: 进程间通讯方式有: 1.内存映射(mmap): 使用mmap函数将磁盘空间映射到内存 2.管道 3.信号 4.套接字(socket) 5.信号机制 通过进程中kill函数,去给另一个函数发送信号&a…

空压机接入配置实例:利用 MODBUS - TCP 转 Ethernet IP 网关实现连接

在工业自动化生产环境中,空压机作为重要的气源设备,其稳定运行和有效监控对于整个生产流程至关重要。然而,不同厂家生产的空压机可能采用不同的通信协议,这给集中监控和管理带来了挑战。在本次案例中,我们遇到的空压机…

基于 Boost.Asio 和 Boost.Beast 的异步 HTTP 服务器(学习记录)

已完成功能: 支持 GET 和 POST 请求的路由与回调处理。 解析URL请求。 单例模式 管理核心业务逻辑。 异步 I/O 技术和 定时器 控制超时。 通过回调函数注册机制,可以灵活地为不同的 URL 路由注册处理函数。 1. 项目背景 1.1 项目简介 本项目是一个基于…

Harmony开发【笔记1】报错解决(字段名写错了。。)

在利用axios从网络接收请求时,发现返回obj的code为“-1”,非常不解,利用console.log测试,更加不解,可知抛出错误是 “ E 其他错误: userName required”。但是我在测试时,它并没有体现为空,…

Spring源码分析之事件机制——观察者模式(二)

目录 获取监听器的入口方法 实际检索监听器的核心方法 监听器类型检查方法 监听器的注册过程 监听器的存储结构 过程总结 Spring源码分析之事件机制——观察者模式(一)-CSDN博客 Spring源码分析之事件机制——观察者模式(二&#xff…

关于Mac中的shell

1 MacOS中的shell 介绍: 在 macOS 系统中,Shell 是命令行与系统交互的工具,用于执行命令、运行脚本和管理系统。macOS 提供了多种 Shell,主要包括 bash 和 zsh。在 macOS Catalina(10.15)之前&#xff0c…

【C++】20.二叉搜索树

文章目录 1. 二叉搜索树的概念2. 二叉搜索树的性能分析3. 二叉搜索树的插入4. 二叉搜索树的查找5. 二叉搜索树的删除6. 二叉搜索树的实现代码7. 二叉搜索树key和key/value使用场景7.1 key搜索场景:7.2 key/value搜索场景:7.3 主要区别:7.4 ke…

【大模型+本地自建知识图谱/GraphRAG/neo4j/ollama+Qwen千问(或llama3)】 python实战(中)

一、建立基本的知识图谱并导入neo4j 这里我举例用的属性表、关系表,大概格式如下 id名字颜色a1苹果红色 startrelenda1属于b1 启动neo4j(关于neo4j的安装此处不再赘述) import pandas as pd from py2neo import Graph, Node, Relationship…

【pyqt】(四)Designer布局

布局 之前我们利用鼠标拖动的控件的时候,发现一些部件很难完成对齐这些工作,pyqt为我们提供的多种布局功能不仅可以让排版更加美观,还能够让界面自适应窗口大小的变化,使得布局美观合理。最常使用的三种布局就是垂直河子布局、水…

解决“KEIL5软件模拟仿真无法打印浮点数”之问题

在没有外部硬件支持时,我们会使用KEIL5软件模拟仿真,这是是仿真必须要掌握的技巧。 1、点击“Project”,然后点击“Options for target 项目名字”,点击“Device”,选择CPU型号。 2、点击“OK” 3、点击“Target”,勾选“Use Mi…

【项目实战1】五子棋游戏

目录 C语言编程实现五子棋&#xff1a;&#xff1a; game.h game.c 1.打印菜单 2.打印棋盘 3.玩家下棋 4.判断五子连珠 5.判断输赢 6.游戏运行 game.c完整源代码展示 test.c C语言编程实现五子棋&#xff1a;&#xff1a; game.h #pragma once #include<stdio.h> …

用ResNet50+Qwen2-VL-2B-Instruct+LoRA模仿Diffusion-VLA的论文思路,在3090显卡上训练和测试成功

想一步步的实现Diffusion VLA论文的思路&#xff0c;不过论文的图像的输入用DINOv2进行特征提取的&#xff0c;我先把这个部分换成ResNet50。 老铁们&#xff0c;直接上代码&#xff1a; from PIL import Image import torch import torchvision.models as models from torch…

Spring Boot 项目自定义加解密实现配置文件的加密

在Spring Boot项目中&#xff0c; 可以结合Jasypt 快速实现对配置文件中的部分属性进行加密。 完整的介绍参照&#xff1a; Spring Boot Jasypt 实现application.yml 属性加密的快速示例 但是作为一个技术强迫症&#xff0c;总是想着从底层开始实现属性的加解密&#xff0c;…

A/B实验之置信检验(一):如何避免误判 (I类) 和漏报 (II类)

假设检验的依据&#xff1a;如何避免误判和漏报 A/B实验系列相关文章&#xff08;置顶&#xff09; 1.A/B实验之置信检验&#xff08;一&#xff09;&#xff1a;如何避免误判和漏报 2.A/B实验之置信检验&#xff08;二&#xff09;&#xff1a;置信检验精要 引言 在数据驱动…

每日一题:链表中环的入口结点

文章目录 判断链表环的入口节点描述数据范围&#xff1a;复杂度要求&#xff1a;输入输出 示例代码实现思路解析注意事项&#xff1a; 判断链表环的入口节点 描述 给定一个链表&#xff0c;判断该链表是否存在环。如果存在环&#xff0c;返回环的入口节点&#xff1b;如果不存…

深度学习blog-Meanshift均值漂移算法-最大熵模型

均值漂移&#xff08;Mean Shift&#xff09;是一种无监督的聚类算法&#xff0c;广泛应用于数据挖掘和计算机视觉任务。它通过移动样本点到其近邻的均值位置来寻找数据的高密度区域&#xff0c;最终形成聚类。 均值漂移算法原理 均值漂移算法的核心思想是通过滑动窗口&#…

51c自动驾驶~合集45

我自己的原文哦~ https://blog.51cto.com/whaosoft/13020031 #运动控制和规划控制需要掌握的技术栈~ 各大垃圾家电造车厂又要开始了~~~​ 1、ROS的通信方式 李是Lyapunov的李&#xff1a;谈谈ROS的通信机制 话题通信和服务通信&#xff0c;其中话题通信是通过发布和订阅…

Python基于jieba和wordcloud绘制词云图

【Cesium】自定义材质&#xff0c;添加带有方向的滚动路线 &#x1f356; 前言&#x1f3b6;一、实现过程✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 Python基于jieba和wordcloud绘制词云图 &#x1f3b6;一、实现过程 读取文本…

计算机网络与服务器

目录 架构体系及相关知识 三层架构&#xff1a; 四层架构&#xff1a; 常见的应用的模式&#xff1a; OSI模型 分层 数据链路层 TCP/IP模型 TCP和UDP都是传输层的协议 TCP三次握手、四次次分手 URL&HTTP协议详解 网址URL 结构化 报文行 报文头 空行 报文体…

Cursor实现go项目配置并实现仓库Gin项目运行

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a;知识备份 ✨特色专栏&#xff1a;知识分享 &#x…