接口示例
(一)接口与回调
回调(callback)是一种常见的程序设计模式。在这种模式中,可以指出某个特定事件发生时应该采取的动作。
假设我们需要做一个定时器,每隔10秒可以发出一个公告,该如何做呢?
package timer;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class TimerTest {
public static void main(String[] args) {
ActionListener listener = new TimePrinter();
Timer t = new Timer(10*1000,listener);
t.start();
JOptionPane.showMessageDialog(null, "Quit program");
System.exit(0);
}
}
class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("At the tone,the time is "+new Date());
Toolkit.getDefaultToolkit().beep();
}
}
从 上面代码中可以看到,TimePrinter类实现了ActionListener接口,覆盖了actionPerformed方法,去打印时间。在main方法中,创建了listener对象,并且创建一个定时器t,t每隔10秒会调用一次接口方法,从而打印时间。
(二)Comparator接口
使用Comparator接口进行排序:
package comparator;
import java.util.Arrays;
import java.util.Comparator;
public class StringLengthSortTest {
public static void main(String[] args) {
Comparator<String> comp = new LengthComparator();
String[] s = {"abcde","bcd","cde"};
Arrays.sort(s, comp);
for(String e : s) {
System.out.println(e);
}
}
}
class LengthComparator implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
int num =o1.length()-o2.length();
if(num==0) {
return o1.compareTo(o2);
}
return num;
}
}
我们认识了Comparator和Comparable两种比较器接口,讨论一下两种比较器的区别:
相同点:实现Comparator接口和Comparable接口都是为了调用Arrays.sort方法,来自定义排序
不同点:
①排序规则实现的方法不同
Comparable接口是实现compareTo(Object obj)
Comparator接口是实现compare(Object o1,Object o2)
②类设计前后不同
comparable接口是在设计类时,就考虑排序问题
comparator接口是在类设计已经完成,还想再对其进行排序
(三)对象克隆
什么是克隆?
克隆就是根据已经有的数据,来创建一份新的完全一样的数据拷贝。
实现克隆的方式?
①使用更改器方法,将原对象中的信息获得后全部set到新的对象中
②使用clone方法,要想使用clone方法也必须满足两个条件:一、要实现Clonable接口;二、使用public修饰符重新定义clone方法
为什么会有浅克隆和深克隆之分?
因为在Java中,分为基本类型数据和引用类型数据,基本类型数据存在于栈内存中,而引用类型数据的地址是在栈内存中,其数据却是在堆内存中。
如果某个对象中全都是基本类型数据,并没有克隆对象中引用的其他对象或者是不可变对象,如String,那么就可以使用默认的克隆操作,也就是浅克隆。
但是通常子对象都是可变的,不全是基本类型数据,那就必须重新定义clone方法来建立一个深拷贝,也就是深克隆。而深克隆的实现就是在引用类型所在的类实现Cloneable接口,并使用public访问修饰符重写clone方法。
package clone;
import java.util.Date;
import java.util.GregorianCalendar;
public class Employee implements Cloneable{//①声明要实现Cloneable接口
private String name;
private double salary;
private Date hireDay;
public Employee(String name,double salary) {
this.name = name;
this.salary=salary;
hireDay = new Date();
}
public Employee clone() throws CloneNotSupportedException{//②使用public修饰,并重新定义clone方法
Employee cloned = (Employee) super.clone();//③对于基本数据类型,使用默认的浅克隆,
cloned.hireDay = (Date) hireDay.clone();//④对于引用类型,使用深克隆
return cloned;
}
public void setHireDay(int year,int month,int day) {
Date newHireDay = new GregorianCalendar(year,month-1,day).getTime();
hireDay.setTime(newHireDay.getTime());
}
public void raiseSalary(double byPercent) {
double raise = salary*byPercent/100;
salary+=raise;
}
public String toString() {
return getClass().getName()+"[name="+name+
",salary="+salary+",hireDay"+hireDay+"]";
}
}
package clone;
/**
* This program demonstrates cloning.
* @author 弓长小月
*
*/
public class CloneTest {
public static void main(String[] args) {
try {
Employee original = new Employee("John Q. Public",78000);
original.setHireDay(2000, 1, 1);
System.out.println("original="+original.toString());
Employee copy = original.clone();
System.out.println("copy="+copy.toString());
System.out.println("---------------------------------------------------");
copy.raiseSalary(10);
copy.setHireDay(2002, 12, 31);
System.out.println("original="+original.toString());
System.out.println("copy="+copy.toString());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}