接口与回调
回调(callback)是一种常见的程序设计模式。在这种模式中,可以指出某个特定事件发生时应该采取的动作。
假设我们构造一个定时器,当达到时间间隔时响一下。
我们可以使用 java.awt.event 包中的 ActionListener 接口,当达到指定的时间间隔时,定时器就会调用接口中的 actionPerformed()。
import java.awt.*;import java.awt.event.*;import java.util.*;import javax.swing.*;import javax.swing.Timer;// to resolve conflict with java.util.Timerpublic class TimerTest {public static void main(String[] args) {ActionListener listener = new TimePrinter();// construct a timer that calls the listener// once every 10 secondsTimer t = new Timer(10000, listener);t.start();JOptionPane.showMessageDialog(null, "Quit program?");System.exit(0);}}class TimePrinter implements ActionListener {public void actionPerformed(ActionEvent event) {System.out.println("At the tone, the time is " + new Date());Toolkit.getDefaultToolkit().beep();}}
Comparator 接口
Arrays.sort() 方法中,有一个版本的参数为一个数组和比较器(commparator),比较器是实现了 Comparator 接口的类的实例,所以就可以自定义数组的排序方式。
java.util.Comparator.java
public interface Comparator<T> {int comapre(T o1, T o2);... some defalut and static method}
如果你要按长度比较字符串,就可以定义一个实现 Comparator
public LenghtComparator implements Comparator<String> {public int compare(String first, String second) {return first.length() - second.length();}}
就可以这样使用:
String[] friends = { "Peter", "Kang", "Jan" };Arrays.sort(friends, new LengthComparator());
对象克隆
Cloneable 接口指示一个类提供了一个安全的 clone 方法。
在开始之前,先了解克隆和拷贝的含义。
使用拷贝,即 = 。原变量和副本都是同一个对象的引用,而拷贝则不同:
不过并没有这么简单,clone 方法是 Object 的一个 protected 方法,只有在 Employee 所在的包里面,你才能调用该克隆方法。并且 Object 中的 clone 方法只能对基本类型进行拷贝,如果对象包含子对象的引用,拷贝域就会得到相同的引用,与拷贝类似。
比如,有一个 Employee 类:
public Employee {String name;double salary;Date hireDay;}
默认的 clone() 是「浅拷贝」,并没有克隆对象中引用的其他对象:
可以看到上述的实例域中,salary 由于是 double 基本类型,所以会克隆一份。但 name 和 hireDay 是对象引用,他们只会引用上一个对象的拷贝。
果子对象属于一个不可变类,如 String,没有更改器方法会改变它,没有方法会生成它的引用,这种情况是允许的。但是,通常子对象是可变的,这时就必须要重新定义 clone() 来建立一个深拷贝,同时克隆所有子对象。
查看源码发现 Cloneable 接口里面什么都没有,其实 Cloneable 并没有实际性的作用,它只是作为一个标记,指示类设计者了解克隆的过程,真正的 clone() 是从 Object 类中继承的。但是,对象对于克隆很「偏执」,如果一个对象请求克隆,但没有实现这个接口,就会生成一个受查异常
Cloneable 接口是 Java 提供的一组标记接口(tagging interface)之一。标记接口不包含任何方法;它唯一的作用就是允许在类型查询中使用 instanceof
上面讲到 Object 类中的 clone() 是 protected 权限。所以,即使是浅拷贝也要重新定义 clone() 为 public:
定义浅拷贝
class Employee implements Cloneable {public Employee clone() throws CloneNotSupportedException {return (Employee) super.clone();}...}
当然深拷贝也要重新定义,并且要克隆对象中可变的实例域:
class Employee implements Cloneable {public Employee clone() throws CloneNotSupportedException {// call Object.clone()Employee cloned = (Employee) super.clone();// clone mutable fieldscloned.hireDay = (Date) hireDay.clone(); // Date 类也是实现了 clone 方法return cloned;}...}
如果在一个对象上调用 clone,但这个对象的类并没有实现 Cloneable 接口,Object 类的 clone 方法就会抛出一个 CloneNotSupportedException。当然,Employee 和 Date 类实现了 Cloneable 接口,所以不会抛出这个异常。不过,编译器并不了解这一点,因此,我们声明了这个异常
如果子类中也有可变类,那子类中要覆盖 clone()。如果没有可变类,可以不覆盖。
所有的数组类型有一个 public 的 clone(),可以用该方法建立一个新数组。
