使用具有公共上限的单个函数覆盖多个泛型函数
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);
}
其中类型 Column
和 Parameter
只是标记接口,用于阻止 Column
在应该使用 Parameter
的地方使用,反之亦然。因此,在幕后,我希望有一个 class 来实现它们,如下所示:
class ObjectSet implements ColumnSet, ParameterSet {
@Override public <V, I extends Input<V>> V getValue(I input) {
...
}
}
从逻辑上讲,ObjectSet.getValue
似乎应该是 ColumnSet.getValue
和 ParameterSet.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);
}
}
我有两个不同的界面
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
只是标记接口,用于阻止 Column
在应该使用 Parameter
的地方使用,反之亦然。因此,在幕后,我希望有一个 class 来实现它们,如下所示:
class ObjectSet implements ColumnSet, ParameterSet {
@Override public <V, I extends Input<V>> V getValue(I input) {
...
}
}
从逻辑上讲,ObjectSet.getValue
似乎应该是 ColumnSet.getValue
和 ParameterSet.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);
}
}