Java接口的变更过程

Java 接口相信所有学过 Java 的人一定都知道,而且 99% 的人一定都背过这个面试题:Java 接口和抽象类的区别是什么?答案都是什么接口方法不能有实现,都是抽象的,接口的方法都默认为 public 修饰等等之类的,这些在 Java 8 之前是正确的,但是随着 Java 的发展,它不再是正确的了。

一起来探索 Java 接口的进化之路。

出生:Java 1.0 引入接口

Java 1.0 ,作为 Java 语言的最初版本,于 1996 年发布。在这个版本中,Java 引入了接口(Interface)这一概念,标志着面向对象编程(OOP)在 Java 中的深入应用。

在 Java 1.0 中,接口被定义为完全抽象的,它具备如下特点:

  • 完全抽象:接口被定义为完全抽象,意味着它不能包含任何方法的具体实现。
  • 只能包含方法签名和常量:接口中只能声明方法签名(没有方法体)和公共静态常量(public static final)。这意味着,在接口中定义的所有字段都会自动成为公共、静态、最终的,而所有方法都被视为公共的和抽象的。
  • 没有构造函数:接口不能被实例化,所以它们不能包含构造函数。
  • 多重实现:不同于类的继承,Java 允许一个类实现多个接口。由于 Java 只允许单继承,所以接口的出现,为 Java 的多重继承提供了实现的可能。
  • 实现类必须实现所有方法:任何一个实现接口的类都必须实现接口中声明的所有方法,除非该类被声明为抽象类。

这个时候定义接口只能定义为如下形式:

public interface MyInterface {String SK_URL = "https://example.com/";String getSeriesUrl();
}

属性 SK_URL 默认为 public static final

Java 1.1 引入内部类,内部类提供了一种强大的机制,它允许将一个类的定义放置在另一个类的定义内部,从而与外部类紧密地绑定在一起。内部类中的匿名内部类,可以用于实现接口,这对接口的使用有着特别的意义,它提高了代码的封装性和可维护性。

会爬了:Java 1.5 引入泛型

Java 5 于 2004 年发布,它引入了泛型,泛型的引入对接口的使用产生了深远的影响。

在引入泛型之前,Java 接口通常处理的是 Object 类型的数据,这意味着任何类型的对象都可以传递给这些接口。在实现类中我们需要将 Object 类型的数据转换为其它具体类型,这种转换可能会导致 ClassCastException。

引入泛型后,接口可以在定义时就指定具体的类型参数,这使得接口在编译时就能够检查和确认数据类型,从而大大增强了类型安全。同时,泛型允许接口定义通用的模板,例如List<E>Comparator<T>,这些接口可以被不同类型的数据重用,而不需要为每种数据类型创建新的接口。

下面举一个简单的例子来说明,引入 泛型对接口好处。

在 Java 5 引入泛型之前,集合类如 List 接口存储的元素类型是不确定的,它们默认存储 Object 类型的对象。这使得集合可以存储任何类型的对象,但也带来了类型安全问题。

List list = new ArrayList();
list.add("skjava.com");
list.add(1); // 这是合法的,因为集合可以存储任何类型的对象// 获取时需要进行类型转换
String str = (String) list.get(0);
Integer num = (Integer) list.get(1);

list 可以同时存储 String 和 Integer。但是,在获取元素时,我们需要进行显式的类型转换。如果在运行时类型不匹配,会抛出 ClassCastException。

引入泛型后,可以在定义集合时指定存储的元素类型。这提高了类型安全,并减少了运行时的错误。

List<String> list = new ArrayList<>();
list.add("skjava.com");
// list.add(1);       // 这行代码会导致编译错误,因为 list 只能存储字符串// 获取时不需要进行类型转换
String str = list.get(0);

list 被定义为仅能存储 String 类型的 List,当尝试添加非 String 类型(如 Integer)到该 list 中会在编译时报错,而不是在运行时。同时,获取元素时也不需要显式的类型转换,因为编译器已经确保了所有元素都是 String 类型。

会走路了:Java 8 引入默认方法和静态方法

Java 8 是一个重大的里程碑,因为它为Java接口引入了两个重要的新特性:默认方法和静态方法,这两个特性让 Java 接口可以走路了。

在 Java 8 之前,接口中申明的方法必须是抽象的,实现该接口就需要实现该接口的所有方法。我们知道接口的设计是一项巨大的工作,因为如果我们需要在接口中新增一个方法,需要对它的所有实现类都进行修改,如果它的实现类比较少还可以接受,如果实现类比较多则工作量就比较大了。而且有些实现类根本不需要实现该方法,也由于 Java 接口的限制导致它强迫实现该方法。

为了解决这个问题,Java 8 引入了默认方法,默认方法允许在接口中添加具有默认实现的方法,它使得接口可以包含方法的实现,而不仅仅是抽象方法的定义。这一特性可以在不破坏现有实现的前提下向接口添加新方法,使得接口具备了向后兼容的能力。

用法如下:

  • 使用default关键字标识方法,然后方法提供具体实现。
public interface MyInterface {default void print() {System.out.println("我是大明哥");}
}

实现接口的类可以直接使用这些默认方法,或者根据需要重写它们:

public class MyInterfaceImpl implements MyInterface{@Overridepublic void print() {System.out.println("我是大明哥 2 号");}
}

Java 8 中还允许在接口中定义静态方法。这些方法与类中的静态方法一样,是属于接口的而不是接口的实例。静态方法主要用于提供辅助方法,例如根据传入参数构建接口的实现,或者提供通用的工具方法。

用法:

  • 静态方法使用static关键字声明,并且必须提供实现。
  • 是通过接口名直接调用静态方法,不需要接口的实例。
public interface MyInterface {static int add(int a, int b) {return a + b;}
}

add() 是通过MyInterface.add(5, 3)直接调用,而不需要创建MyInterface的实例。

Java 引入默认方法和静态方法大大增强了 Java 接口的能力,提高了 Java 接口的灵活性和功能性。

更多关于接口默认方法和静态方法,阅读:Java 8 新特性—接口默认方法和静态方法

可以跑了:Java 9 引入私有方法

Java 8 为引入了默认方法和静态方法,提高了 Java 接口的灵活性和功能性。但是这些依然是 public 的,这在某些情况下会导致了代码重复和封装性不足的问题。为了解决这个问题,Java 9 引入私有方法。

  • 私有方法只能在定义它们的接口内部被访问。这就意味着接口可以有自己的内部逻辑,而不必将所有逻辑都暴露给实现该接口的类。这样,接口的设计者可以更好地控制接口的行为,并防止实现类误用接口内部的代码,增强了接口的封装性。
  • 由于私有方法只能在接口内部使用,无法在接口的实现类中被滥用,这有助于保持接口的一致性和约定。

在接口中使用私有方法有如下几个限制:

  1. 私有方法不能是抽象的。
  2. 私有方法只能在接口内部使用,无法被接口的实现类或外部类访问。
  3. 私有方法不会继承给接口的子接口,每个接口都必须自己定义自己的私有方法。
  4. 私有静态方法可以在其他静态和非静态接口方法中使用。
  5. 私有非静态方法不能在私有静态方法内部使用。

下面是私有方法的简单使用:

public interface MyInterface {private void print() {System.out.println("我是大明哥");}
}

总示例

下面用一个例子来演示上面所有功能。

public interface MyInterface {String NAME = "MyInterface";/*** 抽象方法,所有实现类都要实现* @return*/void abstractMethod();/*** 默认方法*/default void defaultMethod() {//默认方法里可以调用私有方法privateMethod();// 默认方法可以调用静态私有方法staticPrivateMethod();System.out.println("默认方法-MyInterface-defaultMethod");}/*** 静态方法* @return*/static void staticMethod() {// 静态方法只能调用静态私有方法,不能调用私有方法System.out.println("静态方法-MyInterface-staticMethod");}/*** 私有方法*/private void privateMethod() {System.out.println("私有方法-MyInterface-privateMethod");}/*** 静态私有方法*/private static void staticPrivateMethod() {System.out.println("静态私有方法-MyInterface-staticPrivateMethod");}
}

接口 MyInterface 里面定义了抽象方法,默认方法,静态方法,私有方法。这里要注意一下几点:

  1. 私有方法为接口所有,只能在接口的默认方法中调用。
  2. 静态私有方法既可以在静态方法中调用,也可以在默认方法中调用。
  3. 默认方法也可以调用静态方法,但是静态方法不能调用默认方法。
  • 两个实现类
public class MyImplements1 implements MyInterface{@Overridepublic void abstractMethod() {// 调用接口的静态方法MyInterface.staticMethod();System.out.println("抽象方法-MyImplements1-getName");}/*** 重写默认方法*/@Overridepublic void defaultMethod() {System.out.println("重写默认方法-MyImplements1-defaultMethod");}
}public class MyImplements2 implements MyInterface{@Overridepublic void abstractMethod() {// 调用接口的静态方法MyInterface.staticMethod();System.out.println("抽象方法-MyImplements1-getName");}
}

MyImplements1 重写了默认方法。所以当我们调用 MyImplements1 示例对象的 defaultMethod() 时,会调用到重写的这个方法。

  • 测试
public class InterfaceTest {public static void main(String[] args) {MyInterface implements1 = new MyImplements1();MyInterface implements2 = new MyImplements2();implements1.abstractMethod();implements1.defaultMethod();System.out.println("===========================");implements2.abstractMethod();implements2.defaultMethod();}
}
  • 运行结果
静态方法-MyInterface-staticMethod
抽象方法-MyImplements1-getName
重写默认方法-MyImplements1-defaultMethod
===========================
静态方法-MyInterface-staticMethod
抽象方法-MyImplements1-getName
私有方法-MyInterface-privateMethod
静态私有方法-MyInterface-staticPrivateMethod
静态方法-MyInterface-staticMethod
默认方法-MyInterface-defaultMethod

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

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

相关文章

推箱子小游戏C++

推箱子是一款经典的益智游戏&#xff0c;玩家需要通过推动箱子来达到特定的目标。在C中实现这样的小游戏需要考虑游戏逻辑、用户输入、图形界面&#xff08;如果需要的话&#xff09;以及可能的关卡设计。 下面是一个简单的推箱子游戏的实现框架&#xff1a; 定义游戏环境 创建…

DSP问题:CCS更改工程名导入报错

1、问题现象 复制一个工程出来后&#xff0c;修改版本号&#xff0c;重新导入工程后报错。 显示项目描述无效。 2、问题原因 由于CCS无法通过工程描述中找到指定名字文件夹。使用记事本打开.project文件&#xff0c;里面的描述还是以前的文件夹名&#xff0c;所以导入时报…

Spring Boot 开发 -- 静态资源配置详解

一、引言 在开发Web应用程序时&#xff0c;静态资源的管理和配置是一个重要的环节。Spring Boot框架为开发者提供了便捷的静态资源配置方式&#xff0c;使得我们可以轻松地管理如HTML、CSS、JavaScript、图片等静态资源。本文将详细介绍如何在Spring Boot项目中配置和管理静态…

Innodb Buffer Pool缓存机制(三)Innodb Buffer Pool内部组成

一、控制块缓存页 Buffer Pool中默认的缓存页大小和在磁盘上默认的页大小是一样的&#xff0c;都是16KB。为了更好的管理这些在Buffer Pool中的缓存页&#xff0c;InnoDB为每一个缓存页都创建了一些所谓的控制信息&#xff0c;这些控制信息包括该页所属的表空间编号、页号、缓存…

Android基础-AndroidManifest.xml详解

在Android开发中&#xff0c;AndroidManifest.xml 文件是一个至关重要的组成部分&#xff0c;它位于应用的根目录的 app/src/main/ 文件夹下。这个文件提供了Android系统和其他应用所需的所有关于应用的元数据信息。以下是对 AndroidManifest.xml 文件的详细解析。 1. 文件结构…

[Vulfocus解题系列]spring 命令执行(CVE-2022-22947)

环境部署 使用docker部署环境 漏洞等级&#xff1a;高危 3 月 1 日&#xff0c;VMware 官方发布安全公告&#xff0c;声明对 Spring Cloud Gateway 中的一处命令注入漏洞进行了修复&#xff0c;漏洞编号为CVE-2022-22947 Spring官方发布 漏洞描述 使用 Spring Cloud Gate…

javaweb—Vue

重点为&#xff1a;双向数据绑定。 框架&#xff1a;是一个半成品软件&#xff0c;是一套可重用的、通用的、软件基础代码模型&#xff0c;基于框架进行开发&#xff0c;更加快捷&#xff0c;更加高效。 Vue快速入门 基础框架&#xff1a; <!DOCTYPE html> <html lan…

【Python Cookbook】S01E20 fnmatch 模块做字符串匹配

目录 问题解决方案讨论 问题 在不同的操作系统下&#xff0c;怎样做字符串匹配&#xff1f; 解决方案 fnmatch() 模块提供两个函数&#xff0c;fnmatch() 以及 fnmatchcase() 可以用来执行做这样的匹配。 from fnmatch import fnmatch, fnmatchcasematch_res fnmatch(foo.…

vue路由缓存

vue路由缓存 在业务场景中有时候需要页面缓存不清空&#xff0c;那么就需要保留缓存(include为需要缓存&#xff0c;而exclude为不缓存&#xff0c;且优先级大于include) <KeepAlive> 是一个内置组件&#xff0c;它的功能是在多个组件间动态切换时缓存被移除的组件实例…

【java 为什么说 Synchronized 是非公平锁?】

文章目录 概要1. 非公平锁的定义2. synchronized 作为非公平锁的原因3. 非公平锁的特点4. 如何实现公平锁总结 概要 在Java中&#xff0c;synchronized 关键字用于实现同步&#xff0c;以确保在多线程环境下对共享资源的访问是线程安全的。然而&#xff0c;synchronized 实现的…

03-3.1.2 栈的顺序存储的实现

&#x1f44b; Hi, I’m Beast Cheng&#x1f440; I’m interested in photography, hiking, landscape…&#x1f331; I’m currently learning python, javascript, kotlin…&#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以订…

邮件地址搜索软件

易邮件地址搜索大师  一、易邮件地址搜索大师特色 — 易邮件地址搜索大师是一款搜索邮件地址和手机号码的软件&#xff0c;可以按整站搜索&#xff0c;也可以按关键词搜索。使用方法非常简单和方便。 — “整站搜索”可以搜索有很多邮件地址的单一网站&#xff0c;主要用于…

Technart电动螺丝刀TN101控制器维修

Technart电动螺丝刀以其高效、稳定和精确的扭矩控制而闻名。然而&#xff0c;即使优质的产品&#xff0c;在长时间的使用下&#xff0c;也可能会出现TECHNART电动螺母扳手控制器故障。 常见故障及维修方法 1. 控制器不工作 症状&#xff1a;电动螺丝刀无法启动&#xff0c;或启…

Python怎么染色:深入探索Python中的文本和图形着色技巧

Python怎么染色&#xff1a;深入探索Python中的文本和图形着色技巧 在Python编程中&#xff0c;染色或着色不仅限于文本输出&#xff0c;还涉及图形、图像甚至数据可视化的多个层面。本文将带你走进Python的染色世界&#xff0c;从四个方面、五个方面、六个方面和七个方面详细…

【WEEK15】 【DAY2】【DAY3】Email Tasks【English Version】

Continuation from【WEEK15】 【DAY1】Asynchronous Tasks【English Version】 Contents 17. Asynchronous, Timed, and Email Tasks17.2. Email Tasks17.2.1. Email sending is also very common in our daily development, and Springboot provides support for this as well…

用户的权限

一&#xff0c;用户权限基础知识 1&#xff0c;用户的权限有&#xff1a; r&#xff1a;读 w&#xff1a;写 x&#xff1a;执行 2&#xff0c;文件的权限&#xff1a; r&#xff1a;可以执行cat、head、tail等命令读取文件中的内容 w&#xff1a;可以用vi/vim或者重定向等…

JeecgBoot/SpringBoot升级Nacos(2.0.4到2.2.3)启动报错

错误如下&#xff1a; 报这种错误基本就很头大了&#xff0c;是框架不兼容的问题&#xff0c;自己找很难找到解决方法。 解决方案是把SpringBoot框架版本调高。 修改前&#xff1a; <parent><groupId>org.springframework.boot</groupId><artifactId&g…

Dell戴尔XPS 16 9640 Intel酷睿Ultra9处理器笔记本电脑原装出厂Windows11系统包,恢复原厂开箱状态oem预装系统

下载链接&#xff1a;https://pan.baidu.com/s/1j_sc8FW5x-ZreNrqvRhjmg?pwd5gk6 提取码&#xff1a;5gk6 戴尔原装系统自带网卡、显卡、声卡、蓝牙等所有硬件驱动、出厂主题壁纸、系统属性专属联机支持标志、系统属性专属LOGO标志、Office办公软件、MyDell、迈克菲等预装软…

Linux基础 (十四):socket网络编程

我们用户是处在应用层的&#xff0c;根据不同的场景和业务需求&#xff0c;传输层就要为我们应用层提供不同的传输协议&#xff0c;常见的就是TCP协议和UDP协议&#xff0c;二者各自有不同的特点&#xff0c;网络中的数据的传输其实就是两个进程间的通信&#xff0c;两个进程在…

32C3-2模组与乐鑫ESP32­-C3­-WROOM­-02模组原理图、升级口说明

模组原理图&#xff1a; 底板原理图&#xff1a; u1 是AT通信口&#xff0c;wiif-tx wifi-rx 是升级口&#xff0c;chip-pu是reset复位口&#xff0c;GPIO9拉低复位进入下载模式 ESP32-WROOM-32 系列硬件连接管脚分配 功能 ESP32 开发板/模组管脚 其它设备管脚 下载固件…