user508633
user508633

Reputation: 406

Java Generics: Overriding generic methods, wildcard shorthand?

If I have an interface with a generic method like the following:

public interface Thing {
    void <T extends Comparable<? super T>> doSomething(List<T> objects);
}

I need that ugly generic typespec in some places, but most implementations don't actually need it:

public class ICareAboutSortingThing implements Thing {
    @Override
    public void <T extends Comparable<? super T>> doSomething(List<T> objects) { ... }
}

public class IDontCareAboutSortingThingx100 implements Thing {
    @Override
    public void <T extends Comparable<? super T>> doSomething(List<T> objects) { ... }
}

What I would want to write is something like:

public class IDontCareAboutSortingThingx100 implements Thing {
    @Override
    public void <?> doSomething(List<?> objects) { ... }
}

This should be fully typesafe as far as I understand, but is there any variation of this kind of shorthand that would work? I do understand that the compiler doesn't allow overriding with non-generic methods, but this is a case of replacing type arguments with wildcards. My guess is that this isn't actually supported because the compiler could just as easily support

public class IDontCareAboutSortingThingx100 implements Thing {
    @Override
    public void <T> doSomething(List<T> objects) { ... }
}

i.e. overriding with weaker bounds, but that doesn't seem to be allowed. Anyhow, just curious if anyone has a magic incantation for cases like this.

Upvotes: 4

Views: 1795

Answers (3)

Radiodef
Radiodef

Reputation: 37875

Essentially what you're asking for is contravariant method parameters, e.g. a non-generic example looks like:

interface I {
    void m(String s);
}

class C implements I {
    @Override
    public void m(Object o) {}
}

void(Object) is a subsignature of void(String) because the widening conversion is always OK. Java doesn't have this.

For generics, you may override a generic method to be non-generic:

class NotGeneric implements Thing {
    @Override
    public void doSomething(List rawList) {}
}

But you basically shouldn't do it. You will get raw type warnings and you should listen to them. It's available for backwards compatibility.

If it were me, I would just repeat the ugly generic signature because I don't think it's all that ugly.

Something else you could do would be like

interface NonGenericThing extends Thing {
    @Override
    default <T extends Comparable<? super T>>
    void doSomething(List<T> list) {
        doSomethingImpl(list);
    }
    void doSomethingImpl(List<?> list);
}

And then you implement NonGenericThing instead and override doSomethingImpl. (Prior to Java 8, NonGenericThing must be an abstract class.)

Of course that might not be feasible if Thing is actually a large interface. You could also declare Thing this way to begin with, if it's appropriate.

Upvotes: 1

Crazyjavahacking
Crazyjavahacking

Reputation: 9707

You can embed the type information into a class:

public class IDontCareAboutSortingThingx100<T extends Comparable<? super T>> implements Thing<T> {

    @Override
    public void doSomething(List<T> objects) {
    }
}

Upvotes: 0

OldCurmudgeon
OldCurmudgeon

Reputation: 65859

Not quite sure where you're trying to get to but couldn't you encapsulate the restrictions in a separate class?

public class It<T extends Comparable<? super T>> {

    public List<T> them;
}

public interface Thing {

    void doSomething(It<String> them);
}

Upvotes: 4

Related Questions