【问题标题】:Recursive generics递归泛型
【发布时间】:2011-12-07 12:53:54
【问题描述】:

有没有办法使此方法正确通用并消除警告?

/**
 * <p>Sort a collection by a certain "value" in its entries. This value is retrieved using
 * the given <code>valueFunction</code> which takes an entry as argument and returns
 * its value.</p>
 * 
 * <p>Example:</p>
 * <pre>// sort tiles by number
 *Collects.sortByValue(tileList, true, new Function<Integer,NormalTile>() {
 *  public Integer call(NormalTile t) {
 *      return t.getNumber();
 *  }
 *});</pre>
 *
 * @param list The collection.
 * @param ascending Whether to sort ascending (<code>true</code>) or descending (<code>false</code>).
 * @param valueFunction The function that retrieves the value of an entry.
 */
public static <T> void sortByValue(List<T> list, final boolean ascending, @SuppressWarnings("rawtypes") final Function<? extends Comparable, T> valueFunction) {
    Collections.sort(list, new Comparator<T>() {
        @SuppressWarnings({ "unchecked", "rawtypes" })
        @Override public int compare(T o1, T o2) {
            final Comparable v1 = valueFunction.call(o1);
            final Comparable v2 = valueFunction.call(o2);
            return v1.compareTo(v2) * (ascending ? 1 : -1);
        }
    });
}

我尝试了Function&lt;? extends Comparable&lt;?&gt;, T&gt;Function&lt;? extends Comparable&lt;? extends Comparable&gt;, T&gt;,但都没有编译,调用compareTo 时出错。对于前者是:

Comparable 类型中的 compareTo(capture#9-of ?) 方法不适用于参数 (capture#10-of ? extends Comparable)

【问题讨论】:

  • 能否也提供Function类?
  • 嗨,我正在研究这个问题,但并没有真正得到任何结果。但我的一条评论是,不要否定compareTo() 的结果,因为如果有人返回Integer.MIN_VALUE,它将保持Integer.MIN_VALUE 并且排序顺序不会是你想要的。相反,当升序为假时,反转调用,例如从a.compareTo(b)b.compareTo(a);。我知道很烦人...
  • @Grundlefleck 谢谢,我实现了。

标签: java generics unchecked


【解决方案1】:

试试这个:

public static <T, C extends Comparable<? super C>> void sortByValue(List<T> list, final boolean ascending, final Function<C, T> valueFunction) {
    Collections.sort(list, new Comparator<T>() {
        @Override public int compare(T o1, T o2) {
            final C v1 = valueFunction.apply(o1);
            final C v2 = valueFunction.apply(o2);
            return v1.compareTo(v2) * (ascending ? 1 : -1);
        }
    });
}

您还需要super 以允许为子类型定义比较器。更多解释在这里:http://docs.oracle.com/javase/tutorial/extra/generics/morefun.html

更新

另外,查看您的代码,我看到了另一辆自行车,Google Collections 有一个很好的库,它提供了非常方便的Ordering 概念来处理它。

因此,您的代码如下所示:

Ordering<NormalTile> myOrdering = Ordering.natural()
  .onResultOf(new Function<Integer,NormalTile>() {
  public Integer call(NormalTile t) {
      return t.getNumber();
  }))
  .nullsLast();
...
Collections.sort(list, myOrdering);
//or
newList = myOrdering.sortedCopy(readonlyList);

【讨论】:

  • 嗯,你仍然有 Comparable 原始类型......你可能是指 ? super C,而不是 T。在这种情况下,super 是个好主意,但不需要,因为没有其他参数取决于 C
  • 它有效,但我不得不将apply 改回call。而且我已经在使用 Google Collections(在 Guava 中)所以也许我会完全取消这个功能。不过很适合学习泛型。
【解决方案2】:

这对我有用(Eclipse 编译器)

public static <T, U extends Comparable<U>> void sortByValue(
  List<T> list, final boolean ascending, final Function<U, T> valueFunction) {

  Collections.sort(list, new Comparator<T>() {
    @Override
    public int compare(T o1, T o2) {
      final U v1 = valueFunction.call(o1);
      final U v2 = valueFunction.call(o2);
      return v1.compareTo(v2) * (ascending ? 1 : -1);
    }
  });
}

正如其他人所发布的,您甚至可以更进一步,将U 声明为

U extends Comparable<? super U>

如果您有更多的方法参数/返回值取决于U,这将派上用场

【讨论】:

  • 对我来说,该代码将编译,但对该方法的调用不会。调用会是什么样子?
【解决方案3】:

如果为函数声明两个参数会怎样?

public static <T,C extends Comparable<C>> void sortByValue(List<T> list,
    final boolean ascending, final Function<C, T> valueFunction) {
...
final C v1 = ...
final C v2  ...

还没有用编译器检查自己的理智(没有你的接口,我太饿了无法模拟它们:)),但试一试。

我也太昏昏沉沉地无法推断应该是C extends Comparable&lt;C&gt; 还是C extends Comparable&lt;? super C&gt;。我认为前者会起作用并且更通用,尽管在实践中,除了针对自己之外,大多数类都没有实现 Comparable。

【讨论】:

  • 也许也可以使用&lt;T,C extends Comparable&lt;? super C&gt;&gt; 以获得更通用的解决方案
  • @ratchetfreak ha,刚刚编辑了我自己的答案以添加它。 :)。重要问题:“为了更通用的解决方案”,双关语是什么意思?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多