深入理解Java接口
来源:互联网 发布:西游大富翁 java 编辑:程序博客网 时间:2024/06/05 17:51
1. 为什么使用接口
Java中的接口是一组对需求的描述。例如,以下是Comparable<T>接口的定义:
public interface Comparable<T> { int compareTo(T o);}
Comparable<T>接口中定义了一个compareTo方法,这个方法就是它所描述的需求。若我们想调用Arrays.sort方法对一个People对象数组进行比较,那么People对象必须是”可比较的”,即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(...);虽然接口不是类,但我们也可以使用instanceof来判断一个对象是否实现了某个接口:
if (p instanceof Comparable) { ...}我们也可以”继承“一个接口:
public interface InA extends InB { ...}接口还有一个很有用的特性就是一个类可以实现多个接口。其实以上提到的接口特性只要”接口只是一种规范”这个本质来看就很好理解:比如接口中不能实例化、不能含有实例变量,就是因为接口不同于类那样是一个“蓝图”,接口更像一个“标签”。
3.接口与抽象类的比较
4. 接口与回调(callback)
回调(callback)是一种常见的设计模式,利用这种模式,我们可以指出在某个事件发生时应该采取什么动作。比如,Java类库中有个Timer类,可以使通过它在过了指定的时间后发出通知,就像一个闹钟一样。初始化Time类时,需要指定一个时间和到达这个时间后要执行的动作。在这里,告诉Timer要执行的动作就是通过传递给它一个对象,然后到达指定时间后,Timer会调用这个对象的方法。Timer要求我们传递给它的对象需要实现ActionListener接口,这个接口的定义如下:
<span style="font-size:10px;">public interface ActionListener { public void actionPerformed(ActionEvent event);}</span>
我们传递给Time构造器的对象必然定义了actionPerformed方法,我们可以在这个方法中定义我们在定时间隔到达后需要执行的动作。请看以下代码:
<span style="font-size:10px;">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); }} </span>
在以上代码中,会每隔10秒调用一次TimerPrinter中的actionPerformed方法,获取并输出一次当前时间。actionPerformed方法就是回调方法,在回调模式中,通常都是一个类(TimePrinter)实现一个接口(ActionListener),然后另一个类(Timer)的对象通过持有实现该接口的类对象引用(listener)来调用相应的回调方法。
5.参考资料
- 深入理解Java接口
- 深入理解Java接口
- 深入理解Java接口
- 深入理解JAVA接口
- 深入理解Java接口(一)
- 深入理解Java接口(一)
- 深入理解Java接口(一)
- 深入理解Java接口和抽象类
- 深入理解java接口和抽象类
- 深入理解java接口和抽象类
- 深入理解java接口和抽象类
- 深入理解java抽象与接口
- 深入理解接口(转)
- 深入理解SERDES接口
- 接口的深入理解
- 深入理解SERDES接口
- java 深入理解Java的接口和抽象类
- java 深入理解Java的接口和抽象类
- HOOK所有程序的MessageBox
- PHP:对象的高级特性
- 问题 A: 求素数
- 换分币
- android: targetSdkVersion属性说明及其对应不同值会引起的问题
- 深入理解Java接口
- 远程推送(支持iOS 9)
- 解析xml文件的三种方式(sax ,dom ,dom4j)
- phoenixframework 1.4.7 版本发布
- C++第1次实验(提高班)——复习 (2016-03-02) 循环T4
- 25.ELK实时日志分析平台之Kibana介绍及安装
- Java - 内存管理与垃圾收集
- 【Python】搭建redis集群
- rxbag command not find