Java核心技术 卷1-总结-6

news2024/12/23 18:52:34

Java核心技术 卷1-总结-6

  • 接口示例
    • 接口与回调
    • Comparator接口
    • 对象克隆
  • lambda表达式
    • 为什么引入lambda表达式
    • lambda表达式的语法

接口示例

接口与回调

回调(callback)是一种常见的程序设计模式。在这种模式中,可以指出某个特定事件发生时应该采取的动作。 例如,可以指出在按下鼠标或选择某个菜单项时应该采取什么行动。

在java.swing包中有一个Timer类,可以使用它在到达给定的时间间隔时发出通告。例如,假如程序中有一个时钟,就可以请求每秒钟获得一个通告,以便更新时钟的表盘。

在构造定时器时,需要设置一个时间间隔,并告之定时器,当到达时间间隔时需要做些什么操作。 在Java标准类库中的类采用的是面向对象方法。它将某个类的对象传递给定时器,然后,定时器调用这个对象的方法。由于对象可以携带一些附加的信息,所以传递一个对象比传递一个函数要灵活得多。

当然,定时器需要知道调用哪一个方法,并要求传递的对象所属的类实现了java.awt. event包的ActionListener接口。下面是这个接口:

public interface ActionListener {
	void actionPerformed(ActionEvent event);
}

当到达指定的时间间隔时,定时器就调用actionPerformed方法。假设希望每隔10秒钟打印一条信息"At the tone,the time is…",然后响一声,就应该定义一个实现 ActionListener接口的类,然后将需要执行的语句放在actionPerformed方法中。

class TimePrinter implements ActionListener {
	public void actionPerformed(ActionEvent event) {
		System.out.println("At the tone,the time is"+ new Date());
		Toolkit.getDefaultToolkit().beep();
		}
}

actionPerformed方法的ActionEvent参数提供了事件的相关信息,例如,产生这个事件的源对象。

接下来,构造这个类的一个对象,并将它传递给Timer构造器。

ActionListener listener = new TimePrinter();
Timer t = new Timer(10000, listener);

Timer构造器的第一个参数是发出通告的时间间隔,它的单位是毫秒。这里希望每隔10 秒钟通告一次。第二个参数是监听器对象。最后,启动定时器:

t.start();

在定时器启动以后,程序将弹出一个消息对话框,并等待用户点击Ok按钮来终止程序的执行。在程序等待用户操作的同时,每隔10秒显示一次当前的时间。

这个程序除了导入javax.swing.*java.util.* 外,还通过类名导入了javax. swing.Timer。这就消除了javax.swing.Timerjava.util.Timer之间产生的二义性。

Comparator接口

实现了Comparable接口的类的实例可以对一个对象数组进行排序。因为String类实现了Comparable,而且String.compareTo方法可以按字典顺序比较字符串。

现在假设我们希望按长度递增的顺序对字符串进行排序,而不是按字典顺序进行排序。肯定不能让String类用两种不同的方式实现compareTo方法,要处理这种情况,Arrays.sort方法还有第二个版本,有一个数组和一个比较器(comparator)作为参数,比较器是实现了Comparator接口的类的实例。

public interface Comparator<T> {
	int compare(T first, T second);
}

要按长度比较字符串,可以如下定义一个实现Comparator<String>的类:

class LengthComparator implements Comparator<String> {
	public int compare(String first, String second) {
		return first.length() - second.length();
		}
}

具体完成比较时,需要建立一个实例:

Comparator<String> comp = new LengthComparator();
if(comp.compare(words[i],words[j])>0) { ... }

将这个调用与words[i].compareTo(words[j])做比较。这个compare方法要在比较器对象上调用,而不是在字符串本身上调用。
注释:尽管LengthComparator对象没有状态,不过还是需要建立这个对象的一个实例。 我们需要这个实例来调用compare方法——它不是一个静态方法。
要对一个数组排序,需要为Arrays.sort方法传入一个LengthComparator对象:

String [] friends = { "Peter", "Paul", "Mary" };
Arrays.sort(friends, new LengthComparator());

现在这个数组可能是["Paul","Mary","Peter"]["Mary","Paul","Peter"]

对象克隆

Cloneable接口,这个接口指示一个类提供了一个安全的clone方法。
为一个包含对象引用的变量建立副本时原变量和副本都是同一个对象的引用。
在这里插入图片描述

这说明,任何一个变量改变都会影响另一个变量。

Employee original = new Employee("John Public",5000);
Employee copy = original;
copy.raiseSalary(10);// oops--also changed original

如果希望copy是一个新对象,它的初始状态与original相同,但是之后它们各自会有自己不同的状态,这种情况下就可以使用clone方法。

Employee copy = original.clone();
copy.raiseSalary(10);// OK--original unchanged

在这里插入图片描述
clone方法是Object的一个protected方法,只有Employee类可以克隆Employee对象。Object类对于Employee对象一无所知,所以只能逐个域地进行拷贝。如果对象中的所有数据域都是数值或其他基本类型,拷贝这些域没有任何问题。但是如果对象包含子对象的引用,拷贝域就会得到相同子对象的另一个引用,这样一来,原对象和克隆的对象仍然会共享一些信息。
在这里插入图片描述

使用Object类的clone方法克隆一个Employee对象默认的克隆操作是"浅拷贝",并没有克隆对象中引用的其他对象。

浅拷贝会有什么影响吗?这要看具体情况。如果原对象和浅克隆对象共享的子对象是不可变的,那么这种共享就是安全的。如果子对象属于一个不可变的类,如String,或者在对象的生命期中,子对象一直包含不变的常量,没有更改器方法会改变它,也没有方法会生成它的引用,这种情况下同样是安全的。

不过,通常子对象都是可变的,必须重新定义clone方法来建立一个深拷贝,同时克隆所有子对象。在这个例子中,hireDay域是一个Date,这是可变的,所以它也需要克隆。

对于每一个类,需要确定:

  1. 默认的clone方法是否满足要求;
  2. 是否可以在可变的子对象上调用clone来修补默认的clone方法;
  3. 是否不该使用clone。

实际上第3个选项是默认选项。如果选择第1项或第2项,类必须:

  1. 实现Cloneable接口;
  2. 重新定义clone方法,并指定 public 访问修饰符。

必须当心子类的克隆。例如,一旦为Employee类定义了clone方法,任何人都可以用它来克隆Manager对象。Employee克隆方法能完成工作吗?这取决于Manager类的域。在这里是没有问题的,因为 bonus 域是基本类型。但是Manager 可能会有需要深拷贝或不可克隆的域。不能保证子类的实现者一定会修正clone方法让它正常工作。出于这个原因,在Object 类中clone方法声明为protected。

要不要在自己的类中实现clone呢?克隆没有你想象中那么常用。标准库中只有不到5%的类实现了clone。如果你的客户需要建立深拷贝,可能就需要实现这个方法。

lambda表达式

为什么引入lambda表达式

lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。在接口与回调中,已经了解了如何按指定时间间隔完成工作。将这个工作放在一个ActionListener的actionPerformed方法中:

class worker implements ActionListener {
	public void actionPerformed(ActionEvent event) {
	// do some work 
	}
}

想要反复执行这个代码时,可以构造Worker类的一个实例。然后把这个实例提交到一个Timer对象。或者可以考虑如何用一个定制比较器完成排序。如果想按长度而不是默认的字典顺序对字符串排序,可以向sort方法传入一个Comparator对象:

class LengthComparator implements Comparator<String> {
	public int compare(String first, String second) {
		return first.length() - second.length);
		}
	}
Arrays.sort(strings, new LengthComparator();

compare方法不是立即调用。实际上,在数组完成排序之前,sort方法会一直调用compare方法,只要元素的顺序不正确就会重新排列元素。将比较元素所需的代码段放在sort方法中,这个代码将与其余的排序逻辑集成。

这两个例子有一些共同点,都是将一个代码块传递到某个对象(一个定时器,或者一个sort方法)。 这个代码块会在将来某个时间调用。

到目前为止,在Java中传递一个代码段并不容易,不能直接传递代码段。Java是一种面向对象语言,所以必须构造一个对象,这个对象的类需要有一个方法能包含所需的代码。

lambda表达式的语法

再来考虑排序的例子。我们传入代码来检查一个字符串是否比另一个字符串短。这里要计算:

first.length() - second.length()

first和second是什么?它们都是字符串。Java是一种强类型语言,所以我们还要指定它们的类型:

(String first,String second)-> first.length()-second.length()

Java中的一种lambda表达式形式:参数,箭头(->)以及一个表达式。如果代码要完成的计算无法放在一个表达式中,就可以像写方法一样,把这些代码放在{ }中,并包含显式的return语句。例如:

(String first,String second)-> {
	if (first.length()< second.lengthO) return -1;
	else if(first.length()>second.length))return 1;
	else return 0;
}

即使lambda表达式没有参数,仍然要提供空括号,就像无参数方法一样:

()-> { for(int i=100;i >= 0;i--) System.out.println(i); }

如果可以推导出一个lambda表达式的参数类型,则可以忽略其类型。例如:

Comparator<String>comp = (first,second)// Same as(String first,String second)
						-> first.length()- second.length();

在这里,编译器可以推导出firstsecond必然是字符串,因为这个lambda表达式将赋给一个字符串比较器。
如果方法只有一个参数,而且这个参数的类型可以推导得出,那么甚至还可以省略小括号:

ActionListener listener = event ->
System.out.println("The time is "new Date()");
// Instead of (event)->....or(ActionEvent event)->...

无需指定lambda表达式的返回类型。lambda表达式的返回类型总是会由上下文推导得出。 例如,下面的表达式

(String first, String second)-> first.length() - second.length()

可以在需要int类型结果的上下文中使用。

注意∶如果一个lambda表达式只在某些分支返回一个值,而在另外一些分支不返回值,
这是不合法的。例如:

int x)-> { if(x>=0return 1; }

就不合法。

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

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

相关文章

珍藏多年的MySQL函数大全笔记,掌握数据库真不难

做程序员的谁会离得开数据库呢&#xff1f;今天就来分享一下我整理的MySQL的常用函数&#xff0c;基本上囊括了平时要用的函数&#xff0c;它们已经陪我走过了不少年头了&#xff0c;风里来雨里去&#xff0c;缝缝补补又几年&#xff0c;希望能帮到你们&#xff01; 如果数据库…

短视频app开发:如何实现视频直播功能

短视频源码的实现 在短视频app开发中&#xff0c;实现视频直播功能需要借助短视频源码。短视频源码可以提供一个完整的视频直播功能模块&#xff0c;包括视频采集、编码、推流等。因此&#xff0c;我们可以选择一些开源的短视频源码&#xff0c;例如LFLiveKit、ijkplayer等&am…

Nacos简介 安装 配置

简介 什么是注册中心 注册中心在微服务项目中扮演着非常重要的角色&#xff0c;是微服务架构中的纽带&#xff0c;类似于通讯录&#xff0c;它记录了服务和服务地址的映射关系。在分布式架构中&#xff0c;服务会注册到这里&#xff0c;当服务需要调用其它服务时&#xff0c;…

RHCE(六)

目录 1.编写脚本for1.sh,使用for循环创建20账户&#xff0c;账户名前缀由用户从键盘输入&#xff0c;账户初始密码由用户输入&#xff0c;例如: test1、test2、test3、.....、 test10 &#xff08;1&#xff09;编写脚本 &#xff08;2&#xff09;运行脚本 &#xff08;3&…

机器学习——主成分分析法(PCA)概念公式及应用python实现

机器学习——主成分分析法&#xff08;PCA&#xff09; 文章目录 机器学习——主成分分析法&#xff08;PCA&#xff09;一、主成分分析的概念二、主成分分析的步骤三、主成分分析PCA的简单实现四、手写体识别数字降维 一、主成分分析的概念 主成分分析&#xff08;PCA&#x…

华为OD机试真题(Java),分班(100%通过+复盘思路)

一、题目描述 幼儿园两个班的小朋友在排队时混在了一起&#xff0c;每位小朋友都知道自己是否与前面一位小朋友是否同班&#xff0c;请你帮忙把同班的小朋友找出来。 小朋友的编号为整数&#xff0c;与前一位小朋友同班用Y表示&#xff0c;不同班用N表示。 二、输入描述 输…

Android Jetpack - Navigation 组件:进行应用程序导航

一. Navigation 组件的介绍 1.1 什么是 Navigation 组件 Navigation 组件是一种 Android Jetpack 库&#xff0c;它可以帮助开发者轻松地实现应用程序中的导航功能。导航组件包含多个类和组件&#xff0c;包括导航图、目的地、导航控制器等&#xff0c;可以帮助我们管理应用程…

【Node.JS Web编程】记录从语法基础到网络框架的学习过程

文章目录 1. Node.JS 模块系统2. npm使用介绍3. 搭建第一个服务端应用4. GET / POST请求5. Web 前后端分离6. 使用Express框架搭建Web服务7. Request 和 Response8. 中间件9. 使用 Koa 框架搭建Web服务10. 使用 Egg 框架搭建Web服务11. egg 项目结构大全 注意&#xff1a;本次教…

【Linux】uptime命令详解平均负载

命令 ➜ ~ uptime 22:37 up 90 days, 21:45, 2 users, load averages: 2.91 3.46 3.81 具体含义 22:37&#xff1a;代表的是当前的系统时间&#xff0c;也即晚上10点37分。 up 90 days, 21:45&#xff1a;代表系统运行时间 2 users &#xff1a;当前两个用户 load averages: 2…

【Linux】命名管道使用示例-代码实现

文章目录 1 管道基础知识复习(可直接跳转代码实现)1.1 管道的读写规则1.2 管道的特点 2 命名管道2.1 命名管道本质2.2 创建命名管道2.2.1 在命令行创建:2.2.2 在程序中调用函数创建 2.3 命名管道和匿名管道的区别2.4 命名管道的打开规则 3 代码分解实现3.1 makefile书写3.1.1 测…

计算值组成原理 作业8

作业8 题量: 28 满分: 100 作答时间:04-20 09:40至04-26 23:59 100分 一. 单选题&#xff08;共14题&#xff0c;32分&#xff09; 1. (单选题, 2分)计算机硬件能直接执行的只有_____。 A. 算法语言B. 汇编语…

2023-04-22 学习记录--C/C++-数组

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、定义一维数组 ⭐️ &#xff08;一&#xff09;、初识 格式 &#x1f308;&#xff1a;数组元素类型 数组名[数组元素个数]…

Java每日一练(20230423)

目录 1. 数组元素统计 ※ 2. 杨辉三角 II &#x1f31f; 3. 二进制求和 &#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 数组元素统计 定义一个长度为5的数组arr1&a…

【三十天精通Vue 3】第十六天 Vue 3 的虚拟 DOM 原理详解

引言 Vue 3 的虚拟 DOM 是一种用于优化 Vue 应用程序性能的技术。它通过将组件实例转换为虚拟 DOM&#xff0c;并在组件更新时递归地更新虚拟 DOM&#xff0c;以达到高效的渲染性能。在 Vue 3 中&#xff0c;虚拟 DOM 树由 VNode 组成&#xff0c;VNode 是虚拟 DOM 的基本单元…

PTA L1-096 谁管谁叫爹 (20 分)

《咱俩谁管谁叫爹》是网上一首搞笑饶舌歌曲&#xff0c;来源于东北酒桌上的助兴游戏。现在我们把这个游戏的难度拔高一点&#xff0c;多耗一些智商。 不妨设游戏中的两个人为 A 和 B。游戏开始后&#xff0c;两人同时报出两个整数 N A N_A NA​​ 和 N B ​ N_B​ NB​​ 。判…

C语言函数大全-- n 开头的函数

C语言函数大全 本篇介绍C语言函数大全-- n 开头的函数 1. nan 1.1 函数说明 函数声明函数功能double nan(const char *tagp);用于返回一个表示 NaN&#xff08;非数值&#xff09;的 double 类型数字 参数&#xff1a; tagp &#xff1a; 指向字符串的指针&#xff1b;用于…

Tomcat 配置与部署

http 协议就是 http 客户端和 http 服务器之间通信的协议 , 而Tomcat 就是 java 圈子中最广泛使用的 http 服务器. 下载Tomcat Tomcat官网 Tomcat 的版本 , 和后续的 servlet 版本是强相关的 , 此处使用 tomcat 8 , 对应的 servlet 就是 3.1 下载一个 zip 压缩包解压缩即可 T…

探索【Stable-Diffusion WEBUI】的插件:骨骼姿态(OpenPose)

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;骨骼姿态&#xff08;OpenPose&#xff09;系列插件&#xff08;二&#xff09;插件&#xff1a;PoseX&#xff08;三&#xff09;插件&#xff1a;Depth Lib&#xff08;四&#xff09;插件&#xff1a;3D …

Spring之IOC和DI入门案例

IOC和DI入门案例 1. IOC入门案例1.1 门案例思路分析1.2 实现步骤1.3 实现代码1.4 运行结果 2. DI入门案例2.1 DI入门案例思路分析2.2 实现步骤2.3 实现代码2.4 图解演示 1. IOC入门案例 问题导入 <bean>标签中id属性和class属性的作用是什么&#xff1f; 1.1 门案例思…

金三银四总计面试碰壁15次,作为一个27岁的测试工程师.....

3年测试经验原来什么都不是&#xff0c;只是给你的简历上画了一笔&#xff0c;一直觉得经验多&#xff0c;无论在哪都能找到满意的工作&#xff0c;但是现实却是给我打了一个大巴掌&#xff01;事后也不会给糖的那种... 先说一下自己的个人情况&#xff0c;普通二本计算机专业…