使用具有公共上限的单个函数覆盖多个泛型函数

Overriding multiple generic functions with a single function with common upper bounds

我有两个不同的界面

interface ColumnSet {
   <V, I extends Column & Input<V>> V getValue(I column);
}

interface ParameterSet {
   <V, I extends Parameter & Input<V>> V getValue(I value);
}

其中类型 ColumnParameter 只是标记接口,用于阻止 Column 在应该使用 Parameter 的地方使用,反之亦然。因此,在幕后,我希望有一个 class 来实现它们,如下所示:

class ObjectSet implements ColumnSet, ParameterSet {
   @Override public <V, I extends Input<V>> V getValue(I input) {
       ...
   }
}

从逻辑上讲,ObjectSet.getValue 似乎应该是 ColumnSet.getValueParameterSet.getValue 的有效覆盖,因为它接受任何 Input<V> 作为参数,它是两者的上限Column & Input<V>Parameter & Input<V>。但是 Java 9 不认为它覆盖了它们中的任何一个报告 The method getValue() of type ObjectSet must override or implement a generic supertype method.

这是 Java 中泛型的限制还是我遗漏了一些基本的东西?

(显然我无法在 ObjectSet 中创建两个单独的方法,因为它们具有相同的擦除,这让我可以选择为两个 getValue 方法中的两个方法指定不同的名称我试图避免的接口)。

根据m2的签名(§8.4.8.1), an instance method m1 overrides another instance method m2 if the signature of m1 is a subsignature (§8.4.2)

换句话说,重写方法签名应该与重写方法签名或重写方法签名的擦除(§4.6)相同

因此,无法将重写方法参数替换为重写方法中不太具体类型的参数。你可以阅读为什么会这样 here.


在您的情况下,ObjectSet#getValue 签名与 ColumnSet#getValue 签名及其擦除签名 (Object getValue(Column column)) 不同。 ParameterSet#getValue.

也是如此

正如 @samabcde 所指出的,如果基方法是这样声明的:

<V, I extends Column & Input<V>> V getValue(I column);
<V, I extends Parameter & Input<V>> V getValue(I value);

您可以按如下方式实现它们:

@Override
public <V, I extends Column & Input<V>> V getValue(I value) {
    return doGetValue(value);
}

@Override
public <V, I extends Parameter & Input<V>> V getValue(I value) {
    return doGetValue(value);
}

private <V, I extends Input<V>> V doGetValue(I value) { ... }

如果基方法是这样声明的:

<V, I extends Input<V> & Column> V getValue(I value);
<V, I extends Input<V> & Parameter> V getValue(I value);

您只能按如下方式实现擦除:

@Override
public Object getValue(Input value) { ... }

由于这些选项看起来都不太好,我建议按以下方式重新设计您的代码:

public interface Input<R, V> {
    // ...
}
public interface ObjectSet<R> {
    <V> V getValue(Input<R, V> input);
}
public class ObjectSetImpl<R> implements ObjectSet<R> {
    @Override
    public <V> V getValue(Input<R, V> input) {
        // ...
    }
}

现在您可以轻松创建 ObjectSet 只接受具有特定类型参数 Input 的实例 R:

public interface Column<V> extends Input<Column<?>, V> {}
ObjectSet<Column<?>> columnSet = new ObjectSetImpl<>();

如果您不喜欢写 ObjectSet<Column<?>>,您可以创建一个更好命名的 ObjectSet<Column<?>> 实现,将所有工作委托给 ObjectSetImpl:

public class ColumnSet extends DelegatingObjectSet<Column<?>> {}
ColumnSet columnSet = new ColumnSet();

其中 DelegatingObjectSet 是:

abstract class DelegatingObjectSet<R> implements ObjectSet<R> {
    // you can use dependency injection here
    private final ObjectSet<R> delegate = new ObjectSetImpl<>();

    @Override
    public <V> V getValue(Input<R, V> input) {
        return delegate.getValue(input);
    }
}