1

私は2つの異なるインターフェースを持っています

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

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

ここで、型Columnと型は、あるべき場所での使用Parameterを停止するための単なるマーカー インターフェイスであり、その逆も同様です。したがって、舞台裏では、次のように両方を実装する単一のクラスが必要です。ColumnParameter

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

論理的には、との両方に上限がある引数としてany を取るため、とObjectSet.getValueの両方に対して有効なオーバーライドであるように思われます。ただし、Java 9 は、どちらかのレポートをオーバーライドするものとして認識しません。ColumnSet.getValueParameterSet.getValueInput<V>Column & Input<V>Parameter & Input<V>The method getValue() of type ObjectSet must override or implement a generic supertype method

これは Java のジェネリックの制限ですか、それとも基本的なものが欠けていますか?

(明らかに、同じ消去を行うため、2 つの別個のメソッドを作成することはできません。これにより、回避しようとしているインターフェイスでObjectSet2 つのメソッドに異なる名前を付けるという選択肢が残ります)。getValue

4

1 に答える 1

2

(§8.4.8.1)によると、 の署名が の署名のサブ署名 (§8.4.2) である場合、インスタンス メソッドは別のインスタンスメソッドをm1オーバーライドしますm2m1m2

言い換えると、オーバーライド メソッド シグネチャは、オーバーライドされたメソッド シグネチャまたはオーバーライドされたメソッド シグネチャの消去(§4.6)と同じである必要があります

そのため、オーバーライドされたメソッド パラメーターは、オーバーライド メソッド内の特定性の低い型のパラメーターに置き換えることはできません。なぜそうなのかはこちらで読めます。


あなたの場合、署名は署名とその消去署名 ( ) とObjectSet#getValue同じではありません。についても同様です。ColumnSet#getValueObject 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のみを受け入れるインスタンスを簡単に作成できるようになりました。InputR

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 に答える