3

我一直在环顾四周,看看是否能找到可以帮助我解决问题的方法,但直到现在还没有运气。我有以下课程:

  public interface ISort<T> {
      public List<T> sort(List<T> initialList);
  }


  public abstract class Sort<T> implements ISort<T> {
    private Comparator<? super T> comparator;

    public Sort(Comparator<? super T> comparator) {
        this.comparator = comparator;
    }

    @Override
    public List<T> sort(List<T> initialList) {
        ArrayList<T> list = new ArrayList<T>(initialList);
        Collections.sort(list, comparator);

        return list;
    }
  }


public abstract class InternalTreeItem<T> {   
    public abstract String getValue();
}

public class D extends InternalTreeItem<Integer> {
   private Integer i;

   public D(Integer i) {
       this.i = i;
   }

   @Override
   public String getValue() {
       return i.toString();
   }

   public Integer getInteger() {
       return i;
   }
}

public class DComparator implements Comparator<D> {
    @Override
    public int compare(D o1, D o2) {
        return o1.getInteger() - o2.getInteger();
    }
}

public class DSort extends Sort<D> {
    public DSort(Comparator<D> comparator) {
        super(comparator);
    }

    public DSort() {
        super(new DComparator());
    }
}

和测试类:

public class TestClass {
    @Test
    public void test1() {
        List<InternalTreeItem<?>> list= new ArrayList<InternalTreeItem<?>>();

        list.add(new D(1));
        list.add(new D(10));
        list.add(new D(5));

        ISort<?> sorter = new DSort();

        sorter.sort(list);       
    }
}

编译器在该行给出错误

sorter.sort(list);

和状态

The method sort(List<capture#2-of ?>)
in the type ISort<capture#2-of ?>
is not applicable for the arguments
 (List<InternalTreeItem<?>>)

好的,经过几个小时和朋友的帮助,我们意识到问题出sort(List<T> list, Comparator<? super T> c)在抽象类 Sort 中的 Collections# 上,因为我使用Comparator<? extends T>.

我使用泛型,因为我有 2 个模型,一个模型的超类是由 35 个类子类的泛型抽象子类,而第二个模型实际上有 2 个不同的超类,它们组合在一起,又被 35 个类子类化。这些层次结构是给定的,我无法修改它们。

这里的模型非常简单,但你明白了。此外,还有一个工厂,根据 T 的类型,返回一个或另一个分拣机。

任何人都可以为我的问题提供帮助并提供解决方案(即对通用列表进行排序;参数类型可以是通用超类或其子类之一)。

谢谢和最好的问候, 多米

4

3 回答 3

2

解决此问题的一种方法是对无法更改的类使用包装类。

因此,在您的示例中,您希望根据整数值订购对象 D 的列表。通过将您的对象放入包装器中,然后将其添加到列表中,您可以公开您希望对列表进行排序的值。

例如,您可以定义如下接口:

private interface SortableListItem<T> extends Comparable<SortableListItem<T>> {
    public T getValue();
}

然后,为 D 创建一个包装类:

public class DWrapper implements SortableListItem<Integer> {
    private D item;

    public DWrapper(D item) {
        this.item = item;
    }

    public Integer getValue() {
        return item.getInteger();
    }

    public int compareTo(SortableListItem<Integer> o) {
        return getValue().compareTo(o.getValue());
    }
}

从这里创建和排序列表非常简单:

    D item1= new D(1);
    D item2= new D(10);
    D item3= new D(5);

    DWrapper wrapper1 = new DWrapper(item1);
    DWrapper wrapper2= new DWrapper(item2);
    DWrapper wrapper3= new DWrapper(item3);

    List<SortableListItem<Integer>> sortableList = new  ArrayList<SortableListItem<Integer>>();
    sortableList.add(wrapper1 );
    sortableList.add(wrapper2);
    sortableList.add(wrapper3);
    Collections.sort(sortableList);

您当然可以使包装类接受更通用的对象 - 关键是每个对象都返回一个可以对 List 进行排序的值(在本例中为整数)。

于 2010-01-21T16:59:34.250 回答
1

变量sorter的类型为ISort<?>。例如,它可以ISort<String>分配给它。该sort方法接受List<T>where Tcould be的参数String。显然你不能使用List<InternalTreeItem<?>>for List<String>,所以幸运的是编译器指出了错误。

(注意:保持编码约定通常是个好主意。没有I匈牙利语前缀或单字母类名。)

于 2010-01-21T15:30:30.687 回答
0

运行您的代码,我可以推断出您会收到编译错误,因为无法捕获您在下面的类TestClass行中指定的通配符:

ISort<?> sorter = new DSort();

据我了解,通配符的出现代表某些未知类型,并且从您的代码中无法推断出类型(对于编译器)。

但是查看代码,DSort 类不是以获取类型参数的方式编写的,
并且在创建 DSort 实例期间任何传递类型参数的尝试都给出了错误:
The type DSort is not generic; it cannot be parameterized with arguments

但是你提到你不能改变模块的代码(即我假设类 DSort 等)。
因此,解决该错误的一种方法是在创建 ISort 实例期间不使用泛型。
下面的代码有效并打印排序后的输出(1,5,10)

List<InternalTreeItem<?>> list= new ArrayList<InternalTreeItem<?>>();
list.add(new D(1));
list.add(new D(10));
list.add(new D(5));

// no generic arguments
ISort sorter = new DSort();

List<InternalTreeItem<?>> sortedList = sorter.sort(list);

for(InternalTreeItem i:sortedList) {
    System.out.println(i.getValue());
}

但会导致形式为 ISort is a raw type 的警告。对泛型 ISort 的引用应该被参数化。但是拥有使用泛型的代码并警告这种形式并不是一个好习惯。此警告意味着编译器无法对它使用泛型所做的隐式转换提供铸铁保证。

如果可行,我认为更好的解决方案是看看如何重新设计模块类。

于 2010-01-21T15:38:29.267 回答