Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics interface method signature "incorrect"

I had a hard time thinking of a title for this, so do forgive me.

I have an interface with the following methods:

public interface Algorithm<E,F> {
    public Set<? extends Algorithm<E,F>> map(int numPartitions);
    public F reduce(Set<? extends Algorithm<E,F>> partitions);
}

and a class implementing Algorithm with the following methods:

public class LinearSearch<T> implements Algorithm<List<T>, Integer> {
    @Override
    public Set<LinearSearch<T>> map(int numPartitions) {
        return null;
    }

    @Override
    public Integer reduce(Set<LinearSearch<T>> partitions) {
        return null;
    }
}

Now the odd thing is that Eclipse is complaining about the second method, reduce.

The method reduce(Set<LinearSearch<T>>) of type LinearSearch<T> must override or implement a supertype method.

This is despite the fact that the map method is fine. So where am I going wrong?

like image 617
Chris Watts Avatar asked Dec 07 '13 00:12

Chris Watts


2 Answers

Overriding Methods and Parameter Types

On the reduce method, the parameter must be a Set<? extends Algorithm<List<T>,Integer>>. It must take any Set<? extends Algorithm<List<T>,Integer>>, not just a Set<LinearSearch<T>>. You cannot narrow the parameter type while overriding the method.

The JLS, Section 8.4.8.1 elaborates on the signatures of overriding methods:

An instance method m1, declared in class C, overrides another instance method m2, declared in class A iff all of the following are true:

C is a subclass of A.

The signature of m1 is a subsignature (§8.4.2) of the signature of m2.

Either:

m2 is public, protected, or declared with default access in the same package as C, or

m1 overrides a method m3 (m3 distinct from m1, m3 distinct from m2), such that m3 overrides m2.

Here, "subsignature" refers to the parameter types matching, after type erasure.

Overriding Methods and Return Types

But why does the map method work? Because Java allows the developer to narrow the return type of overriding methods on subclasses.

A different section of the JLS, 8.4.5, covers return types in overriding methods:

Return types may vary among methods that override each other if the return types are reference types. The notion of return-type-substitutability supports covariant returns, that is, the specialization of the return type to a subtype.

A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold:

If R1 is void then R2 is void.

If R1 is a primitive type, then R2 is identical to R1.

If R1 is a reference type then:

R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or

R1 = |R2|

(emphasis mine)

like image 66
rgettman Avatar answered Nov 16 '22 11:11

rgettman


Your method header should be as follows

public Integer reduce(Set<? extends Algorithm<List<T>, Integer>> partitions)

In order to override a method you must use exactly the same parameter types. If not, it is not considered to be the same method.

Note that types <E,F> are the parameterized part of that header, so that's where Java gives you some freedom and lets you use the types specified in the class definition.

like image 29
cangrejo Avatar answered Nov 16 '22 12:11

cangrejo