1

我有两个不同的界面

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只是标记接口,以停止在 s 应该Column使用的地方使用Parameters,反之亦然。因此,在幕后,我希望有一个单独的类来实现它们,如下所示:

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

从逻辑上讲,它似乎ObjectSet.getValue应该是两者的有效覆盖,ColumnSet.getValue因为ParameterSet.getValue它将 anyInput<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

4

1 回答 1

2

根据(§8.4.8.1)如果 的签名是的签名的子签名( §8.4.2),则实例方法将m1覆盖另一个实例方法m2m1m2

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

因此,被覆盖的方法参数不能用覆盖方法中不太具体的类型的参数替换。你可以在这里阅读为什么会这样。


在您的情况下,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);
    }
}
于 2020-04-15T01:15:47.327 回答