【问题标题】:Can natural ordering be enforced via Java generic type system?可以通过 Java 泛型类型系统强制执行自然排序吗?
【发布时间】:2017-01-20 22:51:04
【问题描述】:

TreeSet(Collection<? extends E> c)构造函数定义为:

构造一个包含指定集合中元素的新树集,根据其元素的自然顺序排序。插入集合中的所有元素必须实现 Comparable 接口。此外,所有此类元素必须相互可比较:e1.compareTo(e2) 不得为集合中的任何元素 e1 和 e2 抛出 ClassCastException。

是否有可能在语法上强制 Collection&lt;? extends E&gt; 中的 E 实现 Comparable?在上面的 JavaDoc 中,此检查推迟到执行时间...

【问题讨论】:

标签: java generics types


【解决方案1】:

是的,但不是构造函数;您必须公开一个工厂方法,该方法可以对集合类型施加超出整个类所施加的限制。例如,他们可以写

public class TreeSet<E> { ...
  public static <E extends Comparable<? super E>> TreeSet<E>
      create(Collection<? extends E> collection) {
    TreeSet<E> set = new TreeSet<E>();
    set.addAll(collection);
    return set;
  }
  ...
}

【讨论】:

  • 那是因为在class 级别上声明占位符类型E 不受工厂限制?
  • 呃,整个类可以声明限制,方法可以,但是单个构造函数不能。
  • 不,静态与此无关。
  • 也就是说,方法可以在自己的类型参数上声明约束,但不能在调用它的类的类型参数上声明约束(如果它不是静态的)。但是在工厂方法中,您使用方法的类型参数并将其作为 returned 类的类型参数来完成这项工作。
  • 这可能是指出您的示例中存在单独的形式类型参数(具有相同名称)的好时机。 public class TreeSet&lt;E&gt; 中的 E 不是 public static &lt;E extends ...&gt; 中的 E。我倾向于避免在泛型静态方法中重用类形式类型参数符号,以明确区分并避免混淆。
【解决方案2】:

您可以使用这样的工厂方法使您的项目需要它:

public static <T extends Comparable<? super T>> SortedSet<T> safeSortedSet() {
    return new TreeSet<T>();
}

然后是代码:

Set<String> pass = safeSortedSet();
Set<Foo> fail = safeSortedSet();

第二行产生编译错误:

错误:(99, 38) java: 不兼容的类型: 推理变量 T 的边界不兼容
等式约束:Test.Foo
上限:java.lang.Comparable

【讨论】:

    【解决方案3】:

    来自 Tavian Barnes 评论:

    他们本可以完成TreeSet&lt;E extends Comparable&lt;? super E&gt;&gt; 的课程,但是您将无法将自定义比较器用于不可排序的类型。我想不出一种仅在单个构造函数上强制执行此操作的好方法

    所以&lt;E extends Comparable&lt;? super E&gt;&gt; 语法是可能的,但不幸的是,每个泛型extends / super 语法对E 的任何其他类型声明都有最终限制。

    如果 TreeSet 看Creating a TreeSet with a non-Comparable class: why a run-time exception, rather than compile-time error?

    感谢所有帮助回答的人!

    【讨论】:

      猜你喜欢
      • 2010-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-14
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      相关资源
      最近更新 更多