回调
回调是一种常见的程序设计模式。这种模式中,可以指出某个特定事件发生时应该采取的动作。
直接给上代码
package com.java.timer; import java.awt.event.ActionListener; import javax.swing.JOptionPane; import javax.swing.Timer; public class TimerTest { public static void main(String[] args) { // TODO Auto-generated method stub ActionListener listener=new TimePrinter(); Timer t = new Timer(10000,listener); t.start(); JOptionPane.showMessageDialog(null, "Quit program?"); System.exit(0); } }
package com.java.timer; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; public class TimePrinter implements ActionListener { @Override public void actionPerformed(ActionEvent event) { // TODO Auto-generated method stub System.out.println("At the tone,the time is "+new Date()); Toolkit.getDefaultToolkit().beep(); } }
这里调用了java.swing包中的Timer类,可以使用它在给定的时间间隔时发出通告
我们这里可以分析下这段代码。构造一个TimePrinter类调用ActionListener接口,而这个类对这个方法的实现,是通过构造Date对象,紧接着调用静态方法deep()进行提示。
ActionListener listener=new TimePrinter(); 这个语句的意思是声明一个接口类型的变量,然后new一个TimePrinter对象。利用接口型变量对其存储。
紧接着利用Timer方法构造一个定时器,调用接口变量为其中之一的参数,最后调用JOptionPane()方法来构造一个对话框,整个过程就完成了。
这个过程就体现出了回调这个设计模式的思想。在后面的博客中我应该会总结Java的设计模式。
对象克隆
这里要说到对象克隆的知识了。这里我们就会讨论一个Cloneable接口,这个接口只是一个类提供了一个安全的clone()方法。
这里可以举个例子,
Employee original = new Employee("John Public",50000); Employee copy =original; copy.raiseSalary(10);
我们来分析一下这段代码,第一句new了一个Employee对象,将对象存储地址保存在original中,而第二句则将original中存储的对象复制了一份到copy变量中去了,这样的话original和copy指向的都是同一个地址,也就是那个实例地址存储在这两个变量中,所以第三句对copy进行修改,同时也对original进行修改了。
而我们希望拷贝一份与原来无关的变量,那这样就要用到clone方法了。
Employee original = new Employee("John Public",50000); Employee copy = original.clone(); copye.raiseSalary(10);
clone方法是Object的一个protect方法,说明代码不能直接调用这个方法,只有子类或者相同的类才可以克隆父类对象。这个限制是有原因的,我们可以从Object如何实现clone方法来想。因为其对这个对象是一无所知的,只能逐个域的进行拷贝。
这里我们就要讨论一下clone的分类:
它分为深拷贝和浅拷贝
默认的克隆操作是“浅拷贝”,浅拷贝有什么影响,是要看具体情况的,如果原对象和浅克隆对象共享的子对象是不可变的,那么这种共享就是安全的。如果子对象属于一个不可变的类,如String,简而言之,就是所有的量不可改变的量是,浅拷贝是安全的。如果存在可变的量,就要对clone方法建立一个深拷贝。
对于每一个类,需要确定:
1)默认的clone方法是否满足要求;
2)是否可以在可变的子对象上调用clone来修补clone方法;
3)是否不该使用clone;
如果一个对象请求克隆,但并没有实现这个接口,就会生成一个受查异常。Cloneable接口是Java提供的一组标记接口之一,正常接口一般是确保一个类实现一个或一组特定的方法。标记接口不包含任何方法,它唯一的作用是允许在类型查询中使用instanceof。即使浅拷贝实现能满足要求,但还是要实现Cloneable接口,将clone重新定义为public,再调用super.clone()。
代码:
class Employee implements Cloneable { public Employee clone() throws CloneNotSupportedException { return (Employee)super.clone(); } ……}
与Object.clone提供的浅拷贝相比,前面看到的方法并没有增加任何功能,只是将其设为公有的。要建立深拷贝,需要更多工作,克隆对象中可变的实例域。
下面是一个例子:
class Employee implements Cloneable { …… public Employee clone() throws CloneNotSupportedException { Employee cloned =(Employee) super.clone(); Cloned.hireDay=(Date)hireDay.clone(); return cloned; } }
如果都在一个对象上调用clone,但这个对象的类并没有实现Cloneable,这个clone方法就会抛出一个异常。虽然Employee和Date类实现了Clone接口,但是编译器并不知道,所有直接throws这个异常。
这里要注意一个问题,就是子类的克隆,假设我们已经定义了Employee类的clone方法,这时候,就要知道,任何人都会用它来克隆Manager,这时候就要取决于Manager的域了,如果增加的域都是基本数据类型或者是不可变类,那就没有问题,如果不是的话,那就需要重新定义clone方法。
总而言之,其实很简单,浅拷贝就是默认拷贝,不需要克隆对象中的可变实例域,只需要将clone方法定义为public类型就可以了
深拷贝就是需要重新定义clone()方法,使可变类实现拷贝,两者都要对其进行异常处理。