Java核心技术点之接口
1. 为什么使用接口
Java中的接口是一组对需求的描述。接口通过声明接口方法来对外宣布:“要想具有XX功能,就得按我说的做(即实现接口方法)。” 而接口的实现类通过实现相应接口的方法来宣布:“我已经按你说的做了,请赐予我XX功能吧!” 例如,以下是Comparable<T>接口的定义:
public interface Comparable<T> {
int compareTo(T o);
}
Comparable<T>接口中定义了一个compareTo方法,这个方法就是它所描述的需求。也就是说Comparable接口对外宣布:“要想拥有进行比较的功能,得按我说的做(实现compareTo方法)。” 若我们想调用Arrays.sort方法对一个People对象数组进行比较,那么People对象必须是”可比较的”,即People类需要实现Comparable<T>接口。接口的实现类需要实现接口中定义的方法。People类通过实现Comparable<T>接口的方法来宣称:”我已经按你说的做啦,请让我变为可比较的吧!“ 也就是说,接口描述了一组需求,而实现一个接口的类就需要实现这个接口所描述的需求。比如我们想要People类对象是可比较的,我们可以这样:
public class People implements Comparable<People> {
...
public int compareTo(People p) {
//定义具体的比较标准
}
...
}
实际上,Arrays.sort方法之所以要求它所比较的对象需实现了Comparable接口,是因为它在比较对象时调用的对象的compareTo方法(因为它不知道评价一个对象大小的标准,这个标准是由我们来定的)。那么,我们为什么不直接在People类中定义一个compareTo实例方法来定义People对象的比较标准,而是要去实现一个Comparable<T>接口呢?让我们举例来说明以下,假如我们调用了以下代码来对People对象数组peoples进行比较:
Arrays.sort(peoples);
在sort方法内部,实际上调用了类似下面这样的代码来比较People对象:
if (peoples[i].compareTo(peoples[j]) > 0) {
//若为true说明peoples[i] 大于peoples[j]
}
也就是说Arrays.sort方法内部调用了People对象的compareTo方法,那么编译器如何知道People类中确实定义了一个方法呢?若People类没有实现Comparable接口,编译器就只有检查这个类是否实现了这个方法,这样做无疑会增大开销,若接口中的方法不只一个,开销就更大了。而且需要比较的对象可能不只一个,假如后面又有Date对象、Job对象需要我们比较呢?如果每次调用相应对象的compareTo方法都要去检查一下它究竟实现了这个方法没有,将无形中增加很多本不必要的开销。
反过来,我们看看引入接口的好处。People类头部的"implements Comparable<People>“就像是在告诉编译器”我是可比较的,可以直接调用我的compareTo方法而不用检查我有没有这个方法“。这样一来,所有可比较的对象只要实现Comparable<T>接口,编译器就能够知道它一定定义了compareTo方法。一个接口实际上是描述了一种规范,它只说明了这个接口需要实现什么需求,而没有强制规定这个需求如何实现。就像之前我们提到的Comparable<T>接口,需要比较大小的对象不只People对象一个,既然大家都需要比较大小,那索性就来个规定,所有想比较大小的对象的类都实现Compareble<T>接口,统一规定一下可比较的对象究竟该满足什么需求(这里的需求就是compareTo方法)。
2. 接口的特性
Comparable<People> p = new People(...);
if (p instanceof Comparable) {
...
}
我们也可以”继承“一个接口:
public interface InA extends InB {
...
}
接口还有一个很有用的特性就是一个类可以实现多个接口。其实以上提到的接口特性只要”接口只是一种规范”这个本质来看就很好理解:比如接口中不能实例化、不能含有实例变量,就是因为接口不同于类那样是一个“蓝图”,接口更像一个“标签”。
3.接口与抽象类的比较
4. 接口与回调(callback)
回调(callback)是一种常见的设计模式,利用这种模式,我们可以指出在某个事件发生时应该采取什么动作。比如,Java类库中有个Timer类,可以使通过它在过了指定的时间后发出通知,就像一个闹钟一样。初始化Time类时,需要指定一个时间和到达这个时间后要执行的动作。在这里,告诉Timer要执行的动作就是通过传递给它一个对象,然后到达指定时间后,Timer会调用这个对象的方法。Timer要求我们传递给它的对象需要实现ActionListener接口,这个接口的定义如下:
public interface ActionListener {
public void actionPerformed(ActionEvent event);
}
我们传递给Time构造器的对象必然定义了actionPerformed方法,我们可以在这个方法中定义我们在定时间隔到达后需要执行的动作。请看以下代码:
public class TimerTest {
public static void main(String[] args) {
ActionListener listener = new TimePrinter();
Timer t = new Timer(10000, listener);
t.start();
System.exit(0);
}
}
class TimePrinter implements ActionListener {
public void actionPerformed(ActionEvent event) {
Date now = new Date();
System.out.println("The time is " + now);
}
}
在以上代码中,会每隔10秒调用一次TimerPrinter中的actionPerformed方法,获取并输出一次当前时间。actionPerformed方法就是回调方法,在回调模式中,通常都是一个类(TimePrinter)实现一个接口(ActionListener),然后另一个类(Timer)的对象通过持有实现该接口的类对象引用(listener)来调用相应的回调方法。
5.参考资料
Java核心技术点之接口的更多相关文章
- Java核心技术卷一基础知识-第6章-接口与内部类-读书笔记
第6章 接口与内部类 本章内容: * 接口 * 对象克隆 * 接口与回调 * 内部类 * 代理 接口技术主要用来描述类具有什么功能,而并不给出每个功能的具体实现.一个类可以实现(implement)一 ...
- Java核心技术点之泛型
1. Why ——引入泛型机制的原因 假如我们想要实现一个String数组,并且要求它可以动态改变大小,这时我们都会想到用ArrayList来聚合String对象.然而,过了一阵,我们想要实现一个大小 ...
- Java核心技术点之集合框架
1. 概述 Java集合框架由Java类库的一系列接口.抽象类以及具体实现类组成.我们这里所说的集合就是把一组对象组织到一起,然后再根据不同的需求操纵这些数据.集合类型就是容纳这些对象的一个容 ...
- Java核心技术点之内部类
1. 为什么要使用内部类 内部类就是定义在一个类内部的类,那么为什么要使用内部类呢?主要原因有以下几点:第一,内部类中定义的方法能访问到它所在外部类的私有属性及方法:第二,外部类无法实现对同一 ...
- Java核心技术点之动态代理
本篇博文会从代理的概念出发,介绍Java中动态代理技术的使用,并进一步探索它的实现原理.由于个人水平有限,叙述中难免出现不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.概述 1. 什么是代 ...
- java核心技术学习笔记之一程序设计概述
Java 核心技术之一程序设计概述 一. Java语言的特点 简单行 :取经于C++,排除了C++不常用的指针.结构等,增加垃圾回收. 面向对象:与C++不同是单继承,但是可以继承多接口.完全面向 ...
- java核心技术之流与文件
InputStream和OutputStream构成了输入/输出类层次结构的基础.用于按字节进行读写.而与之处在同一等级的Reader/Writer同样作为抽象类定义了用于对字符进行读取的类层次结构, ...
- Java命名和目录接口——JNDI
JNDI即Java命名和目录接口(JavaNaming and Directory Interface),它属于J2EE规范范畴,是J2EE的核心技术之一,提供了一组接口.类和关于命名空间的概念.JD ...
- Java核心技术第五章——1.类、超类、子类(2)
继上一篇Java核心技术第五章——1.类.超类.子类(1) 6.重载解析 假如调用ClassName.Method(args) 1.编译器列出类ClassName所有名为Method的方法. 2.编译 ...
随机推荐
- 关于css属性calc对于ie的态度
做的一个项目,布局的时候用到了max-height:calc(100% - 15px);在谷歌.火狐浏览器,进行下拉的时候,它的父元素会出现垂直滚动条,但是在IE就不可以. 然后在网上找了找,说在它的 ...
- python 视频配音、剪辑
一.FFmpeg的使用 首先下载FFmpeg然后将FFmpeg添加到环境路径中.运行cmd 输入ffmpeg无报错表示成功. 二.python中的使用 在python中执行cmd命令需要调用subpr ...
- QQ空间|qq人气号怎么赚钱?
回报,付出的终极诉求,咱不论情怀. 在<怎么做一个QQ人气号>中,笔者大致提及,打造人气空间的流程,这里简单剖析下QQ人气空间的盈利模式. 关键词:转让,出售,广告,微商,合作,网红,接推 ...
- linux 下的torrent下载器qBitTorrent
BT下载利器--Qbittorrent完全攻 Ubuntu使用命令安装qBittorrent的方法 源码下载
- JS本地保存数据的几种方法
1.Cookie 这个恐怕是最常见也是用得最多的技术了,也是比较古老的技术了.COOKIE优点很多,使用起来很方便 但它的缺点也很多: 比如跨域访问问题:无法保存太大的数据(最大仅为4KB):本地保存 ...
- Canvas在移动端设备上模糊出现锯齿边
在绘制的过程中画布内容的实际大小是根据 canvas 的 width 与 height 属性设置的,而 style 或者CSS设置的width 与 height 只是简单的对画布进行缩放. canva ...
- Sublime Text 3 新手上路:必要的安裝、設定與基本使用教學
http://blog.miniasp.com/post/2014/01/07/Useful-tool-Sublime-Text-3-Quick-Start.aspx
- kafka配置参数详解
Broker Configs Property Default Description broker.id 每个broker都可以用一个唯一的非负整数id进行标识:这个id可以作为broker的 ...
- CentOS6.5进不去系统,修复
今天进系统出现问题了,然后在网上搜索了一下解决方案解决了,把解决方法记录下来,方便以后查阅. 输入root密码 #mount | grep "on /" //得到root用户所在分 ...
- 一文带你了解 Raft 一致性协议的关键点
此文已由作者孙建良授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Raft 协议的发布,对分布式行业是一大福音,虽然在核心协议上基本都是师继 Paxos 祖师爷(lampor ...