Implementing an interface with superclasses of method arguments

As a practical example of a general question in a topic, I would like to implement the containsAll method in the Set interface using

 public boolean containsAll(Iterable<?> c) { /* ... */ } 

I believe this should be allowed since Collection is Iterable , which means that containsAll will cover the interface requirement. Similarly, more generally, the ability to implement interfaces with superclasses of arguments seems to work.

However, Eclipse doesn't say anything (didn't try just javac directly) - can someone explain the reason for this? I am sure that there is something in the specification that does it the way it is, but I would also like to understand the motivation of the requirement. Or am I missing something like Iterable<?> That is not a superclass of Collection<?> ?

As a side question - given that I am declaring two methods, will a method with an Iterable signature always be preferable when calling with the Collection argument?

Eclipse Error:

If I delete the method using the signature of the Collection , leaving Iterable one (see after the error), I get the following:

The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)

Exact implementation:

 @Override public boolean containsAll(Collection<?> c) { for (Object o : c) if (!contains(o)) return false; return true; } public boolean containsAll(Iterable<?> c) { for (Object o : c) if (!contains(o)) return false; return true; } 
+6
java method-signature interface
source share
3 answers

My guess is why java has this limitation, let's say you have:

 class A { void foo(String s) { ... } } class B extends A { // Note generalized type @Override void foo(Object s) { ... } } 

Now, if you have class C extends B and it wants to override foo , it is not clear which argument it should take.

Let's say, for example, C extended A directly first, overriding void foo(String s) , and then it was changed for extension B. In this case, C, the existing override foo will become invalid, since B foo should be able to process all Object s, not only String s.

+2
source share

Since the implemented interface declares the (abstract) method containsAll(Collection<?>) , You must implement it with this exact signature. Java does not allow you to implement / override a method with a wider parameter type than the original. This is why you get an error message that you show when you comment on your method using the Collection signature.

You are not showing the other error that you are claiming to get when the method is not commented out, but I assume that this could do something with an ambiguous method overload.

+5
source share

Argument types are part of the method signature, so jvm needs a method with the exact same signature to search for overrides. A containsAll (Iterable) will have a different signature than containsAll (Collection).

If I remember correctly, the compiler should use some workarounds to make generics work despite this limitation.

For your second question, the compiler will prefer the Collection argument because it is a subtype of Iterable, which makes the Collection method more specific than Iterable.

0
source share

All Articles