1 接口概念
- 接口的概念与使用方法
- 接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式定义方法。
例如:如果要使用Arrays.sort方法,那么对象所属的类必须实现了Comparable接口。 - 接口不能包含成员变量,只能包含方法和常量。
- Java SE8之后可以在接口中提供简单方法,这些方法不能引用成员变量。
- 实现接口的步骤如下:
1)将类声明为实现给定的接口。
2)对接口中的方法进行定义。
class Employee implements Comparable{
public int compareTo(Object otherObject){
}
}
class Employee implements Comparable<Employee>{
}
- 接口的特性
- 接口不是类,不能使用new运算符实例化,但是可以声明接口的变量,接口变量必须引用实现了接口的类对象:
Comparable x;
- 可以使用instanceof检查一个对象是否实现了某个特定接口:
if(anObject instanceof Comparable){
}
- 接口与抽象类
- 为什么不用抽象类来代替接口呢?Java中一个类只能有一个父类,但可以有多个接口。如果一个类要继承多个抽象类的方法,使用抽象类就不行了。
在C++中允许多重继承。但也由此带来了一系列复杂特性和效率问题。
- 静态方法
- Java SE8中允许在接口中添加静态方法,但通常的做法是将静态方法放在伴随类中,在标准库中可以看到成对出现的接口和实用工具类,如Path/Paths。
- 现在可以为Path接口添加方法,那样Paths类就没有存在的意义了,但要改写整个标准库是不可能的。因此伴随类的方法还很有用。只是自己实现方法时不再需要另外写一个伴随类。
- 默认方法
- 可以为接口方法提供一个默认实现,需要用default修饰符标记此方法。
- 在Java SE8中,可以为接口的所有方法提供默认方法,这样程序员只需要关心他们需要的方法。
- 以前的版本不支持默认方法,如果为接口添加了新方法,那么老的代码的类由于没有实现此方法会无法通过编译,解决办法是将新增方法设为默认方法。
- 解决默认方法冲突
- 超类优先:如果在类的超类和接口中有同名方法,那么超类的方法优先。因此千万不能让默认方法重定义Object类中的方法,由于超类优先原则,这样做将没有任何意义。
- 接口冲突:如果一个类包含了多个接口有同名方法,且至少有一个接口的方法有默认实现,那么就必须覆盖此方法而不能使用默认方法,可以在覆盖的方法中再选择调用某个接口的默认方法。
class Student implements Person,Named
{
public String getName()
{
return Person.super.getName();
}
}
2 接口示例
- 监听接口
Java中的消息响应函数需要通过接口来实现,例如Timer类定时器,在构造时需要传入一个包含了ActionListener接口的对象,定时调用其actionPerformed方法。示例:
package alarmClock;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class TimerTest {
public static void main(String[] args) {
ActionListener listener=new TimePrinter();
Timer timer=new Timer(10000, listener);
timer.start();
JOptionPane.showMessageDialog(null, "123");
System.exit(0);
}
}
class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Ding");
Toolkit.getDefaultToolkit().beep();
}
}
- Comparator接口
假如我们想要按照字符串的长度对String对象进行排序而不是字典顺序,String类又不允许我们覆盖,该怎么办呢。
Array.sorts方法提供了第二个版本,一个数组和一个比较器,比较器是实现了Comparator接口的类的实例。
类似于STL中的传入仿函数的办法。
public interface Comparator<T>
{
int compare(T first,T second);
}
class LengthComparator implements Comparator<String>
{
public int compare(String first,String second)
{
return first.length()-second.length();
}
}
Comparator<String> comp=new LengthComparator();
String[] words={"123","123124","2"};
Arrays.sort(words,comp);
- Cloneable接口
- 在Java中对象之间的拷贝是浅拷贝,也就是将一个对象变量直接赋值给另一个变量,它们只是两个引用指向了同一个对象。
- 要实现深拷贝就必须调用clone方法,返回一个新的对象,在此新的对象上进行操作不会修改原对象。
- Object对象实现了clone方法,但是是protected的。因此子类只能对自己类型的对象调用clone方法,而不能调用其它类型对象的clone方法。
- Cloneable接口不包含任何方法,只是一个标记,将clone方法写为public的,表示可以调用父类的clone方法。
- 如果要实现彻底的深拷贝,就要重写clone方法,将类中的每一个引用所指的对象也进行拷贝。或者通过其他方法。