有时我们有几个类,它们的某些方法具有相同的签名,但不对应于已声明的 Java 接口。例如,JTextField
和JButton
(以及 中的其他几个 javax.swing.*
)都有一个方法
public void addActionListener(ActionListener l)
现在,假设我希望对具有该方法的对象做一些事情;然后,我想要一个接口(或者自己定义它),例如
public interface CanAddActionListener {
public void addActionListener(ActionListener l);
}
这样我就可以写:
public void myMethod(CanAddActionListener aaa, ActionListener li) {
aaa.addActionListener(li);
....
但是,可悲的是,我不能:
JButton button;
ActionListener li;
...
this.myMethod((CanAddActionListener)button,li);
这种演员阵容是非法的。编译器知道这JButton
不是a CanAddActionListener
,因为该类尚未声明实现该接口......但是它“实际上”实现了它。
这有时会带来不便——Java 本身已经修改了几个核心类来实现由旧方法(String implements CharSequence
例如 )组成的新接口。
我的问题是:为什么会这样?我理解声明一个类实现一个接口的实用性。但是无论如何,看看我的例子,为什么编译器不能推断出类JButton
“满足”接口声明(查看它的内部)并接受强制转换?是编译器效率的问题还是有更根本的问题?
我对答案的总结:在这种情况下,Java 可以允许一些“结构类型”(有点像鸭子类型 - 但在编译时检查)。它没有。除了一些(对我来说不清楚)性能和实现方面的困难之外,这里还有一个更基本的概念:在 Java 中,接口(通常是所有东西)的声明不仅仅是结构性的(具有这些签名)但语义:这些方法应该实现一些特定的行为/意图。因此,在结构上满足某些接口的类(即,它具有具有所需签名的方法)不一定在语义上满足它(一个极端的例子:回想一下“标记接口”,它甚至没有方法!)。因此,Java 可以断言一个类实现了一个接口,因为(并且仅仅是因为)它已被显式声明。其他语言(Go、Scala)有其他的哲学。