Java泛型:覆盖泛型方法,通配符shorthand?

Java Generics: Overriding generic methods, wildcard shorthand?

如果我有一个带有如下通用方法的接口:

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

我在某些地方需要那种丑陋的通用类型规范,但大多数实现实际上并不需要它:

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) { ... }
}

我想写的是这样的:

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

据我所知,这应该是完全类型安全的,但是这种 shorthand 有任何变体可以工作吗?我知道编译器不允许用非泛型方法覆盖,但这是用通配符替换类型参数的情况。我的猜测是这实际上不受支持,因为编译器可以很容易地支持

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

即用较弱的界限覆盖,但这似乎是不允许的。无论如何,只是好奇是否有人对这种情况有神奇的咒语。

不太确定你想去哪里,但你不能把限制封装在一个单独的 class 中吗?

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

    public List<T> them;
}

public interface Thing {

    void doSomething(It<String> them);
}

您可以将类型信息嵌入到 class:

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

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

本质上你要求的是逆变方法参数,例如一个非通用示例如下所示:

interface I {
    void m(String s);
}

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

void(Object)void(String) 的子签名,因为扩大转换总是可以的。 Java 没有这个。

对于泛型,您可以将泛型方法覆盖为非泛型:

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

但你基本上不应该这样做。你会得到 raw type warnings,你应该听听他们的意见。它可用于向后兼容。

如果是我,我会重复丑陋的通用签名,因为我不认为它有那么丑陋。

您还可以做其他事情,例如

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

然后您改为实施 NonGenericThing 并覆盖 doSomethingImpl。 (在Java8之前,NonGenericThing必须是一个摘要class。)

当然,如果Thing实际上是一个大接口,那可能不可行。如果合适,您也可以以这种方式开始声明 Thing