有三个类,他们之间的关系如下:
interface A
class B implements A
class C implements A
要获得B类的对象,一般的写法是:B b = new B();
还有一种写法,叫接口回调,写法是:A b = new B();
意思是,用接口的变量b,去引用B的对象。接着就可以用b去调用B中的方法。但调用的方法必须是接口里定义了的。
接口回调带来的最大好处就是灵活性,例如必要时可以直接用b去引用C的对象:b = new C();
例子
interface People {
void peopleList();
}
class Student implements People {
public void peopleList(){
System.out.println("I’m a student.");
}
}
class Teacher implements People {
public void peopleList() {
System.out.println("I’m a teacher.");
}
}
public class Example {
public static void main(String args[]) {
People a; // 声明接口变量
a = new Student(); // 实例化,接口变量中存放对象的引用
a.peopleList(); // 接口回调
a = new Teacher(); // 实例化,接口变量中存放对象的引用
a.peopleList(); // 接口回调
}
}
输出:
I’m a student.
I’m a teacher.
概念就是这样。下面说开发中的常见的例子。
最最常见的接口回调的例子就是
List list = new ArrayList();
这里的List就是接口,ArrayList是普通类。(如下图,白色是接口,红色的普通类。)
List list = new ArrayList(); 这种写法正是接口回调的写法。这时,list只能调用接口List中定义了的方法。
假如,你在写一个很大的第三方库,并决定用LinkedList来实现这个库的核心。如果你的这个库非常依赖于访问list里的元素,最后你会发现使用LinkedList(访问时间O(n))是个非常糟的设计。这时候你才意识到,应该用ArrayList(访问时间O(1)) 。
如果你之前是使用接口回调的写法,那么做这个改变十分容易。只要这样修改一下:
List list = new LinkedList();
改为
List list = new ArrayList();
而如果你用普通的写法,LinkedList list = new LinkedList()来实现你的核心库,那么修改就不那么容易了。因为不能保证其余代码没有使用LinkedList类专属的方法。
总而言之,这个选择仅仅是一个设计的问题......但这种设计是(尤其是工作在大型项目时)非常重要,因为它可以让你不用破坏现有的代码,就能实现特殊的改变。