mts*_*tsz 10 java eclipse generics wildcard javac
作为Eclipse中的Java泛型编译的后续编译,但不是在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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在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);
^
Run Code Online (Sandbox Code Playgroud)
Foo<?>使用Foo<String>上面的代码片段替换将在javac中编译,这意味着该问题与使用的通配符有关.由于Eclipse编译器应该更宽容,因此代码段可能不是有效的Java吗?
(我使用javac 1.6.0_37和Eclipse Indigo编译器合规级别1.6)
(EDIT1:包含在EDIT2中删除的另一个示例.)
EDIT2:暗示着无可争辩的,比较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;
}
Run Code Online (Sandbox Code Playgroud)
(在上面的方法定义中简单替换Comparable<T>with Foo<?>.)因此,对于javac和imho来说,在概念上比较任何Foo<A>和它似乎是安全的Foo<B>.但是asSortedList,如果使用通配符对其类型参数进行参数化,则仍然无法编写返回泛型集合的排序列表表示的泛型方法.我试图"欺骗"的javac代Foo<?>通过S extends Comparable<S>中asSortedFooList,但这并没有工作.
编辑3:后来Rafaelle指出,设计中存在缺陷,因为实施Comparable<Foo<T>>不是必需的,并且实现Comparable<Foo<?>>提供相同的功能,通过精细设计解决初始问题.
(最初的原因和好处是,a Foo<T>可能在某些目的上并不关心其具体类型,但仍然使用具体类型的T实例,为了其他目的,它实例化.该实例不必用于确定其他Foos中的顺序,因为它可能在API的其他部分中使用.
具体示例:假设每个Foo都使用不同的类型参数进行实例化T.每个实例Foo<T>都有一个递增的id类型int,用于实现compareTo-method.我们现在可以对这些不同类型的列表进行排序,Foo并且不关心具体类型T(表示它Foo<?>),并且仍然具有T可供以后处理的具体类型的实例.)
对我来说这是另一个javac错误。当您尝试将 a 发送Collection<Foo<?>>到带有签名的方法时:
public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c)
Run Code Online (Sandbox Code Playgroud)
编译器注意到形式参数 T有一个上限,因此检查调用者是否遵守约束。type参数是参数化 type 的(通配符)实例,因此如果is-a 则Foo<T>测试将通过。基于通用定义:Foo<?> Comparable<Foo<?>>
class Foo<T> implements Comparable<Foo<T>>
Run Code Online (Sandbox Code Playgroud)
我想说这是真的,所以 Eclipse 再次是对的,但javac有一个错误。安吉莉卡·兰格 (Angelika Langer) 的这篇文章链接永远不够。另请参阅相关 JLS。
您问它是否类型安全。我的答案是它是类型安全的,它表明你的设计有缺陷。考虑一下您虚构的Comparable<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;
}
}
Run Code Online (Sandbox Code Playgroud)
你总是回来0,所以问题没有被发现。但是当您尝试使其有用时,您有两个选择:
T会员该String字段始终是 a String,因此您并没有真正从类型变量中受益T。另一方面,T没有其他可用的类型信息,因此compareTo()您只能处理普通对象,并且类型参数再次无用。您可以通过实现来实现相同的功能Comparable<Foo<?>>
| 归档时间: |
|
| 查看次数: |
1761 次 |
| 最近记录: |