我希望继承泛型类和接口。有一个我无法理解的问题。该问题反映在以下简化代码中:
public interface A1 <T extends F1<?>> {
public void compare(T f1, T f2);
}
public class F1 < T extends A1<? extends F1<T>> >
{
T a;
public void compare(F1<T> f) {
a.compare(this, f);
}
}
A1
位于A1.java
,F1
位于F1.java
。
我收到编译时错误:
The method compare(capture#1-of ? extends F1<T>, capture#1-of ? extends F1<T>)
in the type A1<capture#1-of ? extends F1<T>> is not applicable for the
arguments (F1<T>, F1<T>)
我需要A1 < ? extends F1< T>>
来继承F1
。
我想有2个等级(&#34; O&#34;而不是&#34; F&#34;,&#34; C&#34;而不是&#34; A&#34;):
O1
,O2
...)包含对象的所有相关信息以及&#34;比较器&#34; (任何分析一对相同类型的2个对象的函数)。对象的类定义了它接受的比较器的类型,主要要求是比较器应该接受托管对象类型的2个对象。例如,O1
只能接受比较O1
的所有比较器,O2
可以有接受O2
的比较器。C1
,C2
...)本身。他们比较层次结构1中的对象。两个层次结构中的每个元素都添加了在子类中使用的补充功能。
让我们考虑以下用例,这是通过这些层次结构的路径之一:
O1
有2个成员(不是类型!):val
(任何类型),cmp
(类型C1
仅接受O1
)。 C1_1
没有相应的对象O
,但它实现了与集合相关的其他功能。它可以比较对象(&#34;基本&#34;类型如int
,String
,TColor
和&#34;复杂&#34;对象O
&#39 ; s)在集合中并应用仅返回1个值(例如最大值)的聚合器。
如果集合是基本类型,则cmp2
用于比较集合中的元素。对于集合中的复杂对象,可以使用它们的集成比较器。C1_1_1
实现了如何比较对象列表(1:1)。 C1_1_2
(未提供)可用于比较对象集,例如与十字架产品。O1_1
的{{1}}类val
TVALB
和比较extend List<TVALA>
。 C1_1_1
的其他子类可以有更精细的实现来比较基本对象和复杂对象。
支持代码:
C1_1_1/2
我使用依赖注入来为特定类中的比较器(public abstract class O1 <TVAL, TC extends C1<? extends O1<TVAL>>>
{
TVAL val;
TC cmp;
public double compare(O1<TVAL, TC> o) {
return cmp.compare(this, o);
}
}
public interface C1 <TO extends O1<?, ?> > {
public double compare(TO t1, TO t2) {
// ...
}
}
public abstract class C1_1 <
TVALA,
TVALB extends Collection<TVALA>,
TO extends O1<TVALB, ?>
>
extends C1 <TO> {
Cmp2<TVALA, Double> cmp2;
IAggregator<TVALA> aggr;
Double compare(TO o1, TO o2) {
return aggr.apply(
compPairs(o1.val, o2.val, cmp2)
);
}
abstract pairs<TVALA> compPairs(
TVALB b1
, TVALB b2
, Cmp2<TVALA> cmp2);
// aggregation
public static class Aggr1<TVALA> implements IAggregator<TVALA> {
public Double apply(pairs<TVALA> pairs) {
//...
}
}
public static class Aggr2<TVALA> implements IAggregator<TVALA> {
// ...
}
}
public abstract class C1_1_1 <
TVALA,
TVALB extends List<TVALA>,
TO extends O1<TVALB, ?>
>
extends C1_1 <TO> {
pairs<TVALA> compPairs(
TVALB b1
, TVALB b2
, Cmp2<TVALA> cmp2) {
// ...
}
}
public abstract class O1_1 <
TVALA extends O1<?,?>,
TVALB extends List<TVALA>
, TC extends C1_1_1<TVALA, TVALB, ? extends O1_1<TVALA, TVALB, TC>>>
extends O1<TVAL>
{
// ...
}
- 树到对象C
)分配。因此,这种方法(如果可行的话)可以灵活地为特定类型的对象选择合适的比较器。
答案 0 :(得分:1)
让我们首先重命名类型变量,因为两个T代表不同的东西,希望它能让事情更清晰:
public interface A1 <T extends F1<?>> {
public void compare(T t1, T t2);
}
public class F1 < S extends A1<T extends F1<S>> >
{
S s;
public void compare(F1<S> f) {
s.compare(this, f);
}
}
现在您看到您实际上在compare
上调用了s
,这是A1<T>
的一个实例,其中T
可以是F1<S>
的子类。但是,您传递的参数类型为F1<S>
,而不是子类T
,这正是编译器所说的。
基本上你使方法参数变得协变,可能它们应该是逆变的。为此,请使用super
代替extends
:
public class F1 < S extends A1<? super F1<S>> >
{
S s;
public void compare(F1<S> f) {
s.compare(this, f);
}
}
答案 1 :(得分:1)
问题是a
的类型为A1<? extends F1<T>>
,即通过通配符进行参数化。您不能再调用A1<?>.compare
,因为编译器不知道?
代表什么特定类型。
对于这个更简单的代码,您会看到相同的行为:
A1<? extends Object> a = ...;
a.compare(new Object(), new Object());
如果我正确理解您的用例,您只希望能够在特定比较器上参数化F1
。所以看起来你应该能够做到这一点:
interface A1<A extends A1<A>> {
public void compare(F1<A> f1, F1<A> f2);
}
class F1<A extends A1<A>> implements Comparable<F1<A>> {
A a;
@Override
public void compareTo(F1<A> f) {
a.compare(this, f);
}
}
请注意,我已F1
实施Comparable
,因为这是一种很好的做法。
答案 2 :(得分:1)
您可以删除A1
课程,只需使用Comparable
界面。
public class F1<T extends Comparable<T>> implements Comparable<F1<T>> {
T t;
@Override public int compareTo(F1<T> other){
return t.compareTo(other.t);
}
}