Java8实战-总结38

news2024/10/1 17:37:24

Java8实战-总结38

  • 默认方法
    • 概述默认方法
    • 默认方法的使用模式
      • 可选方法
      • 行为的多继承

默认方法

概述默认方法

默认方法是Java 8中引入的一个新特性,希望能借此以兼容的方式改进API。现在,接口包含的方法签名在它的实现类中也可以不提供实现。缺失的方法实现会作为接口的一部分由实现类继承(所以命名为默认实现),而无需由实现类提供。

那么,该如何辨识哪些是默认方法呢?其实非常简单。默认方法由default修饰符修饰,并像类中声明的其他方法一样包含方法体。比如,可以像下面这样在集合库中定义一个名为Sized的接口,在其中定义一个抽象方法size,以及一个默认方法isEmpty

public interface Sized { 
	int size(); 
	
	//默认方法
	default boolean isEmpty() { 
		return size() == 0; 
	} 
} 

这样任何一个实现了Sized接口的类都会自动继承isEmpty的实现。因此,向提供了默认实现的接口添加方法就不是源码兼容的。

现在,回顾一下最初的例子,那个Java画图类库和你的游戏程序。具体来说,为了以兼容的方式改进这个库(即使用该库的用户不需要修改他们实现了Resizable的类),可以使用默认方法,提供setRelativeSize的默认实现:

default void setRelativeSize(int wFactor, int hFactor) { 
	setAbsoluteSize(getWidth() / wFactor, getHeight() / hFactor); 
} 

默认方法在Java 8API中已经大量地使用了。Collection接口的stream方法就是默认方法。List接口的sort方法也是默认方法。很多函数式接口,比如Predicate、Function以及Comparator也引入了新的默认方法,比如Predicate.and或者Function.andThen(记住,函数式接口只包含一个抽象方法,默认方法是种非抽象方法)。

Java 8中的抽象类和抽象接口
那么抽象类和抽象接口之间的区别是什么呢?它们不都能包含抽象方法和包含方法体的
实现吗?
首先,一个类只能继承一个抽象类,但是一个类可以实现多个接口。
其次,一个抽象类可以通过实例变量(字段)保存一个通用状态,而接口是不能有实例变
量的。

默认方法的使用模式

默认方法有两种用例:可选方法和行为的多继承。

可选方法

可能碰到过这种情况,类实现了接口,不过却刻意地将一些方法的实现留白。以Iterator接口为例来说。Iterator接口定义了hasNext、next,还定义了remove方法。Java 8之前,由于用户通常不会使用该方法,remove方法常被忽略。因此,实现Iterator接口的类通常会为remove方法放置一个空的实现,这些都是些毫无用处的模板代码。

采用默认方法之后,可以为这种类型的方法提供一个默认的实现,这样实体类就无需在自己的实现中显式地提供一个空方法。比如,在Java 8中,Iterator接口就为remove方法提供了一个默认实现,如下所示:

interface Iterator<T> { 
	boolean hasNext(); 
	T next(); 
	default void remove() {  
		throw new UnsupportedOperationException(); 
	} 
} 

通过这种方式,可以减少无效的模板代码。实现Iterator接口的每一个类都不需要再声明一个空的remove方法了,因为它现在已经有一个默认的实现。

行为的多继承

默认方法让之前无法想象的事儿以一种优雅的方式得以实现,即行为的多继承。这是一种让类从多个来源重用代码的能力,如下图所示:
在这里插入图片描述
Java的类只能继承单一的类,但是一个类可以实现多接口。要确认也很简单,下面是Java API中对ArrayList类的定义:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable, Iterable<E>, Collection<E> { 
//继承唯一一个类,但是实现了六个接口
} 
  1. 类型的多继承
    这个例子中ArrayList继承了一个类,实现了六个接口。因此ArrayList实际是七个类型的直接子类,分别是:AbstractList、List、RandomAccess、Cloneable、Serializable、IterableCollection。所以,在某种程度上,早就有了类型的多继承。

由于Java 8中接口方法可以包含实现,类可以从多个接口中继承它们的行为(即实现的代码)。从一个例子入手,看看如何充分利用这种能力来为我们服务。保持接口的精致性和正交性能帮助你在现有的代码基上最大程度地实现代码复用和行为组合。

  1. 利用正交方法的精简接口
    假设需要为你正在创建的游戏定义多个具有不同特质的形状。有的形状需要调整大小,但是不需要有旋转的功能;有的需要能旋转和移动,但是不需要调整大小。这种情况下,怎么设计才能尽可能地重用代码?

可以定义一个单独的Rotatable接口,并提供两个抽象方法setRotationAnglegetRotationAngle,如下所示:

public interface Rotatable { 
	void setRotationAngle(int angleInDegrees); 
	int getRotationAngle(); 
	
	//rotateBy方法的一个默认实现
	default void rotateBy(int angleInDegrees) { 
		setRotationAngle((getRotationAngle () + angle) % 360); 
	} 
} 

这种方式和模板设计模式有些相似,都是以其他方法需要实现的方法定义好框架算法。
现在,实现了Rotatable的所有类都需要提供setRotationAnglegetRotationAngle的实现,但与此同时它们也会天然地继承rotateBy的默认实现。

类似地,可以定义之前看到的两个接口MoveableResizable。它们都包含了默认实现。下面是Moveable的代码:

public interface Moveable { 
	int getX(); 
	int getY(); 
	void setX(int x); 
	void setY(int y); 
	
	default void moveHorizontally(int distance){ 
		setX(getX() + distance); 
	} 
	
	default void moveVertically(int distance){ 
		setY(getY() + distance); 
	} 
} 

下面是Resizable的代码:

public interface Resizable { 
	int getWidth(); 
	int getHeight(); 
	void setWidth(int width); 
	void setHeight(int height); 
	void setAbsoluteSize(int width, int height); 
	
	default void setRelativeSize(int wFactor, int hFactor) { 
		setAbsoluteSize(getWidth() / wFactor, getHeight() / hFactor); 
	} 
} 
  1. 组合接口
    通过组合这些接口,现在可以为游戏创建不同的实体类。比如,Monster可以移动、旋转和缩放。
public class Monster implements Rotatable, Moveable, Resizable { 
//需要给出所有抽象方法的实现,但无需重复实现默认方法} 

Monster类会自动继承Rotatable、MoveableResizable接口的默认方法。这个例子中,Monster继承了rotateBy、moveHorizontally、moveVerticallysetRelativeSize的实现。

现在可以直接调用不同的方法:

Monster m = new Monster(); //构造函数会设置Monster的坐标、高度、宽度及默认仰角
m.rotateBy(180); //调用由 Rotatable 中继承而来的rotateBy
m.moveVertically(10); //调用由Moveable中继承而来的moveVertically

假设现在需要声明另一个类,它要能移动和旋转,但是不能缩放,比如说Sun。这时也无需复制粘贴代码,可以像下面这样复用MoveableRotatable接口的默认实现。下图是这一场景的UML图表。

public class Sun implements Moveable, Rotatable {}

在这里插入图片描述
像游戏代码那样使用默认实现来定义简单的接口还有另一个好处。假设需要修改moveVertically的实现,让它更高效地运行。可以在Moveable接口内直接修改它的实现,所有实现该接口的类会自动继承新的代码(这里我们假设用户并未定义自己的方法实现)。

关于继承的一些错误观点
继承不应该成为你一谈到代码复用就试图倚靠的万精油。比如,从一个拥有100个方法及
字段的类进行继承就不是个好主意,因为这其实会引入不必要的复杂性。完全可以使用代理
有效地规避这种窘境,即创建一个方法通过该类的成员变量直接调用该类的方法。这就是为什
么有的时候我们发现有些类被刻意地声明为final类型:声明为final的类不能被其他的类继
承,避免发生这样的反模式,防止核心代码的功能被污染。注意,有的时候声明为final的类
都会有其不同的原因,比如,String类被声明为final,因为我们不希望有人对这样的核心
功能产生干扰。
这种思想同样也适用于使用默认方法的接口。通过精简的接口,你能获得最有效的组合,
因为你可以只选择你需要的实现。	

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

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

相关文章

静电除尘器的工作原理及使用说明

静电除尘器是一种通过静电场将空气中的颗粒物带电并吸附到电极上&#xff0c;再利用机械振打或气流将颗粒物从电极上清除的空气净化设备。以下是静电除尘器的工作原理及使用说明&#xff1a; 工作原理&#xff1a; 静电除尘器主要由电极系统、电源系统、收尘系统、清灰系统等…

计算机的分类

文章目录 前言一、超级计算机二、大型计算机三、迷你计算机&#xff08;服务器&#xff09;四、工作站五、微型计算机 前言 世界上所有的计算机总共分为五类&#xff1a;超级计算机、大型计算机、迷你计算机、工作站、微型计算机。今天就简单介绍下各自特点和用途。 一、超级计…

allegro pcb designer铜皮合并

前提&#xff0c;两块铜皮是同一个网络 现在是没有合并的状态 第一步选中两块铜皮 点击sharpe菜单&#xff0c;点击merge shape子菜单&#xff0c;两块铜皮就合并了。

字符输入转换流字符输出转换流

字符输入转换流&字符输出转换流 字符输入转换流&字符输出转换流 package newTest;import java.io.*;public class test2 {//目标&#xff1a; 掌握字符输入转换流public static void main(String[] args) {try(//文件管道对象//得到原始的字节编码InputStream fsnew Fi…

2023-2024年云赛道模拟题库

2023-2024年云赛道模拟题库上线啦&#xff0c;全面覆盖云计算&#xff0c;云服务&#xff0c;大数据和人工智能考点&#xff0c;都是带有解析&#xff0c;实时更新&#xff0c;永久使用 参赛对象及要求&#xff1a; 参赛对象&#xff1a;现有华为ICT学院及未来有意愿成为华为…

一个CPU是怎么寻址的?

目录 CISC vs RISC 概念和历史 CISC vs RISC 对比举例&#xff1a;X86的CAS(做原子操作的) 对比举例&#xff1a;ARM的CAS(做原子操作的) 指令寻址 指令中的操作数的寻址方式 各语言对象内存布局对比 C内存布局 理解编译单元 Java对象内存布局 python对象模型 CPU …

Linux 基金会分叉 Terraform,正式推出 OpenTofu

导读Linux 基金会宣布推出 OpenTofu&#xff0c;这是一个 Terraform 的开源替代方案&#xff0c;并且分叉自 Terraform。OpenTofu 原名 OpenTF&#xff0c;为所有人提供了一个在中立治理模式下的可靠的开源替代方案。 Terraform 是 HashiCorp 开源的一个安全和高效的用来构建、…

JavaScript中的深拷贝(deep copy)和浅拷贝(shallow copy)

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

突发!该国教育部将MDPI、Hindawi和Frontiers三大出版商打包“拉黑”了!

最近&#xff0c;基于对学术诚信和作者署名的特别关切&#xff0c;马来西亚大学教育部发布了一项声明&#xff0c;禁止该国的公立大学使用政府预算来支付在MDPI、Hindawi和Frontiers三家学术出版商旗下的所有期刊上发表论文的费用。 马来西亚大学教育部还成立了一个特别委员会…

MyCat-web安装文档:安装Zookeeper、安装Mycat-web

安装Zookeeper A. 上传安装包 zookeeper-3.4.6.tar.gzB. 解压 #解压到当前目录&#xff0c;之后会生成一个安装后的目录 tar -zxvf zookeeper-3.4.6.tar.gz#加上-c 代表解压到指定目录 tar -zxvf zookeeper-3.4.6.tar.gz -C /usr/local/C. 在安装目录下&#xff0c;创建数据…

Attention Is All You Need(中文版)

目录 1 简介 2 背景 3 模型结构 3.1 编码器和解码器 3.2 注意力机制 3.2.1 缩放的点积注意力机制 3.2.2 多头注意力机制 3.2.3 Transformers中的注意力机制 3.3 基于位置的前馈神经网络 3.4 词嵌入和 softmax 3.5 位置编码 4 为什么选择自注意力机制 5 训练 5.1 硬件和时间 5.2…

深眸科技自研AI视觉分拣系统,实现物流行业无序分拣场景智慧应用

在机器视觉应用环节中&#xff0c;物体分拣是建立在识别、检测之后的一个环节&#xff0c;通过机器视觉系统对图像进行处理&#xff0c;并结合机械臂的使用实现产品分类。 通过引入视觉分拣技术&#xff0c;不仅可以实现自动化作业&#xff0c;还能提高生产线的生产效率和准确…

java案例25:批量操作文件管理器

思路&#xff1a; 编写文件管理器&#xff0c;实现文件的批量操作。具体功能&#xff1a; 1.用户输入指令1&#xff0c;代表“指定关键字检索文件”&#xff0c; 此时需要用户输入检索的目录和关键字&#xff0c; 系统在用户指定的目录下检索出文件名中包含关键字的文件 并将其…

抢先知:公抓抓 信息挖掘工具

随着经济全球化进程的加速&#xff0c;企业在不断发展和壮大&#xff0c;同时也在不断地适应市场的变化。在这个过程中&#xff0c;企业信息的及时获取和掌握变得至关重要。那么&#xff0c;最新企业信息哪里找呢&#xff1f;在这里介绍几个路径&#xff0c;可以参考&#xff0…

蓝桥杯每日一题2023.10.9

题目描述 成绩统计 - 蓝桥云课 (lanqiao.cn) 题目分析 学会使用四舍五入函数round #include<bits/stdc.h> using namespace std; int s1, s2; int main() {int n, x;cin >> n;for(int i 1; i < n; i ){cin >> x; if(x > 60)s1 ;if(x > 85)s2 ;…

GD32F103 硬件SPI通信

1. SPI的通信原理 SPI既可以做主机也可以做从机。 当做主机时。MOSI&#xff0c;SCK,CS都是作为输出。 而作为从机时。MOSI&#xff0c;SCK,CS都是作为输入。 所以SPI的硬件电路应该实现这样的功能。 2. GD32/STM32的SPI框图 1. GD32框图 如下图做主机的数据流向&#xf…

华为HCIP安全 VPN学习笔记 密码学基础:基本框架介绍

0.学习密码学的目的与方法 作为一个工程师&#xff0c;你不需要像科学家一样掌握密码学的整个开发过程。 为了保障安全性&#xff0c;密码学发展出不同的模块&#xff0c;解决了不同的问题&#xff0c;数据的安全性也在这个过程中不断提升。而加密只是其中众多模块之一。其他…

JAVA毕业设计098—基于Java+Springboot的在线教育课程视频(源码+数据库)

基于JavaSpringboot的在线教育课程视频(源码数据库)098 一、系统介绍 本系统分为管理员、教师、用户三种角色(角色菜单可自行分配) 用户功能&#xff1a; 注册、登录、课程搜索、视频观看、课程资料发布、资料浏览、用户中心、我的发布、通知信息、密码修改 教师功能&…

母婴店怎么在微信小程序卖东西

随着互联网的发展&#xff0c;微信小程序已经成为一种新型的电商模式&#xff0c;它无需下载安装&#xff0c;使用方便&#xff0c;不占用手机内存&#xff0c;让购物变得更加简单便捷。母婴店也可以通过微信小程序来销售产品&#xff0c;拓宽销售渠道&#xff0c;增加销售额。…

Docker Mysql实战:docker compose 搭建Mysql

1、docker-compose-mysql文件准备 进入/home/docker目录&#xff0c;新建docker-compose-mysql.yml文件&#xff0c;内容如下&#xff1a; version: 3.0 services:mysql:image: "mysql:5.7"container_name: "mysql"environment:MYSQL_ROOT_PASSWORD: &q…