Sometimes we have several classes that have some methods with the same signature, but that don't correspond to a declared Java interface. For example, both JTextField
and JButton
(among several others in javax.swing.*
) have a method
public void addActionListener(ActionListener l)
Now, suppose I wish to do something with objects that have that method; then, I'd like to have an interface (or perhaps to define it myself), e.g.
public interface CanAddActionListener {
public void addActionListener(ActionListener l);
}
so that I could write:
public void myMethod(CanAddActionListener aaa, ActionListener li) {
aaa.addActionListener(li);
....
But, sadly, I can't:
JButton button;
ActionListener li;
...
this.myMethod((CanAddActionListener)button,li);
This cast would be illegal. The compiler knows that JButton
is not a CanAddActionListener
, because the class has not declared to implement that interface ... however it "actually" implements it.
This is sometimes an inconvenience - and Java itself has modified several core classes to implement a new interface made of old methods (String implements CharSequence
, for example).
My question is: why this is so? I understand the utility of declaring that a class implements an interface. But anyway, looking at my example, why can't the compiler deduce that the class JButton
"satisfies" the interface declaration (looking inside it) and accept the cast? Is it an issue of compiler efficiency or there are more fundamental problems?
My summary of the answers: This is a case in which Java could have made allowance for some "structural typing" (sort of a duck typing - but checked at compile time). It didn't. Apart from some (unclear for me) performance and implementations difficulties, there is a much more fundamental concept here: In Java, the declaration of an interface (and in general, of everything) is not meant to be merely structural (to have methods with these signatures) but semantical: the methods are supposed to implement some specific behavior/intent. So, a class which structurally satisfies some interface (i.e., it has the methods with the required signatures) does not necessarily satisfies it semantically (an extreme example: recall the "marker interfaces", which do not even have methods!). Hence, Java can assert that a class implements an interface because (and only because) this has been explicitly declared. Other languages (Go, Scala) have other philosophies.