Java泛型与通配符在Eclipse中编译,但不在javac中

前端之家收集整理的这篇文章主要介绍了Java泛型与通配符在Eclipse中编译,但不在javac中前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
作为后续的 Java generics compile in Eclipse,but not in javac,我发布另一个在Eclipse中编译和运行良好的代码段,但在javac中引发了一个编译错误. (这样可以防止该项目从Maven构建中提取代码段.)

自包含的片段:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class Main {
  public static void main(String[] args) {
    Set<Foo<?>> setOfFoos = new HashSet<Foo<?>>();
    List<Foo<?>> sortedListOfFoos = asSortedList(setOfFoos);
  }


  public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c) {
    List<T> list = new ArrayList<T>(c);
    java.util.Collections.sort(list);
    return list;
  }


  public static class Foo<T> implements Comparable<Foo<T>> {
    @Override
    public int compareTo(Foo<T> o) {
      return 0;
    }
  }
}

javac中的编译返回:

Main.java:11: <T>asSortedList(java.util.Collection<T>) in Main cannot be applied to (java.util.Set<Main.Foo<?>>)
    List<Foo<?>> sortedListOfFoos = asSortedList(setOfFoos);
                                    ^

取代Foo与Foo< String>上面的代码段将在javac中编译,这意味着问题与使用的通配符相关.由于Eclipse编译器应该更宽容,所以代码片段可能不是有效的Java?

(我使用javac 1.6.0_37和Eclipse Indigo,编译器符合级别1.6)

(EDIT1:包括在EDIT2中被删除的另一个例子)

EDIT2:irreputable提示,比较Foo A和Foo B可能在概念上是错误的,灵感来自seh的答案,一个工作的asSortedFooList可以写成如下:

public static <T extends Foo<?>> List<T> asSortedFooList(Collection<T> c) {
    List<T> list = new ArrayList<T>(c);
    java.util.Collections.sort(list);
    return list;
}

(在上述方法定义中用Foo< T>简单替换可比较的< T>)
所以对于javac和imho来说似乎是安全的,在概念上对比任何Foo< A>和Foo B.但是,如果类型参数用通配符参数化,则仍然无法编写通用方法asSortedList,该方法返回一个通用集合的排序列表表示.我试图通过替换Foo<?>“欺骗”javac通过S扩展可比较< S>在asSortedFooList中,但这没有工作.

EDIT3:Rafaelle后来指出,设计中存在缺陷,因为实现了可比较的< Foo>>不是必需的,并且实现可比较的< Foo>>提供相同的功能,通过精心设计解决初始问题.

(最初的原因和好处是,Foo&T可能在某些目的上不关心其具体类型,但仍然使用具体类型T的实例,为了其他目的,它被实例化,这种情况不必用于确定其他Foos之间的顺序,因为它可能用于API的其他部分.

具体示例:假设每个Foo用T的不同类型参数实例化.Foo的每个实例具有类型int的递增id,用于实现compareTo方法.我们现在可以对这些不同类型的Foo进行排序,并且不关心具体的类型T(用Foo表示),并且还有一个具体类型T的实例可以进行后续处理.)

解决方法

对我来说这是另一个javac bug.当您尝试发送Collection< Foo<?>>具有签名的方法
public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c)

编译器注意到形式参数T有一个上限,所以检查被约束是否受到调用者的尊重. type参数是参数化类型Foo< T>的(通配符)实例化,因此如果Foo<> is-a Comparable< Foo<>>.基于通用定义:

class Foo<T> implements Comparable<Foo<T>>

我会说这是真的,所以Eclipse是正确的,javac有一个错误.这个Angelika Langer’s entry从来没有足够的联系.另见the relevant JLS.

你问是否类型安全?我的答案是它是类型安全的,它表明你的设计有缺陷.考虑您的虚拟实施可比较的< T>界面,我添加了两个字段:

public static class Foo<T> implements Comparable<Foo<T>> {

  private T pState;
  private String state;

  @Override
  public int compareTo(Foo<T> other) {
    return 0;
  }
}

你总是返回0,所以没有发现问题.但是当您尝试使其有用时,您有两个选择:

>比较字符串字段
>比较T成员

String字段始终是一个String,所以你不会从类型变量T中受益.另一方面,T没有其他类型的信息可用,所以在compareTo()中,你只能处理一个普通的对象,并且再次该类型参数是无用的.您可以通过实现Comparable< Foo<?>>>实现相同的精确功能.

猜你在找的Java相关文章