Reputation: 469
Suppose we have an interface A
, being implemented by class B
:
public interface A {
public int getValueForName(String name);
}
public class B implements A {
public int getValueForName(String name) {
//implementation
}
public String getNameForValue(int value) {
//implementation
}
}
If programmers consistently use type A
every time an instance of B
is referred to, then any method, say getNameForValue()
, defined in B
but not specified in A
is hidden and cannot be accessed by any code holding a reference of type A
.
It seems that there is a fatal flaw with this approach. How can a piece of code referring to an instance of B
(with type A
) access getNameForValue()
?
Upvotes: 1
Views: 190
Reputation: 61526
Look at it from a more real life example. If I am blindfolded and you tell me that there is a household pet in front of me what can I do with it? Probably pet it would be all. Now if you tell me it is a hamster I would also be able to put it in a wheel for it to run around (my cat on the other hand would not go for that idea).
When you have a variable declared as an interface (or a higher level class), such as your A
it is the same as the household pet in the example above. As such not all of the methods will be accessible to you.
To know if it is a hamster, or a B
you must remove the blindfold. In the case of Java that would mean calling instanceof
and then casting the variable to a B
. You need the instanceof
to make sure that the cast is safe. Unless, of course, you know that the thing is a B
, in which case you may want to actually declare it to be a B
to begin with instead.
If you find yourself casting you probably have done something "wrong" with your design. It is rare, since Java got generics, to have to cast anymore.
Upvotes: 1
Reputation: 180788
How can a piece of code referring to an instance of B (with type A) access getNameForValue()?
By casting the instance to type B.
One of the purposes of an interface is to define methods that are common to two or more types. That doesn't mean that you're going to define interface methods for every possible combination of every possible type, but only those methods that are common to all types that you wish to expose via the interface.
So by definition, having an instance of the interface type presumes that there may be methods in the original type which you are not going to have access to through the interface. That's just how it works.
Another reason you might have an interface is to specify a capability. So if a class is Iterable, that means it can be iterated. If I'm trying to get an Iterable instance, I care about the methods in the class that implement Iterable's methods, but I don't care about any other methods, because they don't have anything to do with the Iterable capability.
In short, it's a feature, not a flaw.
Upvotes: 1
Reputation: 106430
The real flaw is that the contract of the interface isn't being respected. If I'm using the interface, I shouldn't care about any other methods except those defined in the interface.
If the interface does not define the method that I want to work with, then either the interface needs to be updated to accommodate that new method, or I need to use a different interface.
Take, for instance, Collection
. If I have an instance that is bound to the contract of Collection
, then I have access to an Iterator
. However, I know that the elements I'm getting back are of type List
, and I want to make use of the ListIterator
instead, which is more powerful.
The problem is that Collection
does not define any way for me to access a ListIterator
. So, I have but one option (since I can't just go and update the Collection
interface needlessly): use the List
interface instead.
If you run into this scenario in your own code, your interfaces are not supporting the methods that they need to be. Add that support at the interface level instead of at the instance level.
Upvotes: 3