gpt4 book ai didi

带有通配符的 Java 泛型在 Eclipse 中编译,但在 javac 中不编译

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:59:25 24 4
gpt4 key购买 nike

作为 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 和编译器合规级别为 1.6 的 Eclipse Indigo)

(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;
}

(在上面的方法定义中用 Comparable<T> 简单替换 Foo<?>。)因此,对于 javac 和恕我直言,在概念上比较任何 Foo<A> 似乎是安全的。和 Foo<B> .但是还是不能写出泛型方法asSortedList如果其类型参数使用通配符进行参数化,则返回泛型集合的排序列表表示形式。我试图通过替换 Foo<?> 来“欺骗”javac通过 S extends Comparable<S>asSortedFooList ,但这没有用。

EDIT3: 稍后 Rafaelle指出,自从实现Comparable<Foo<T>>以来,设计存在缺陷没有必要,并实现 Comparable<Foo<?>>提供相同的功能,通过改进设计解决最初的问题。

(最初的原因和好处是,一个 Foo<T> 可能在某些目的不关心它的具体类型,但仍然使用一个具体类型的实例 T ,它被实例化为, 用于其他目的。该实例不必用于确定其他 Foo 中的顺序,因为它可能用于 API 的其他部分。

具体示例:假设每个 Foo 都被实例化为 T 的不同类型参数. Foo<T> 的每个实例具有类型为 int 的递增 ID用于执行 compareTo -方法。我们现在可以对这些不同类型的列表进行排序 Foo并且不关心具体类型 T (用 Foo<?> 表示)并且 仍然 有一个具体类型的实例 T可供以后处理。)

最佳答案

对我来说这是另一个 javac漏洞。当您尝试发送 Collection<Foo<?>>到具有签名的方法:

public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c)

编译器注意到形式参数 T有一个上限,所以检查调用者是否遵守约束。 类型参数 是参数化类型 Foo<T> 的(通配符)实例化, 所以如果 Foo<?> 测试将通过是一个 Comparable<Foo<?>> .基于通用定义:

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

我会说这是真的,所以 Eclipse 再次是正确的 javac有一个错误。这Angelika Langer's entry永远没有足够的联系。另见 the relevant 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;
}
}

你总是返回0 ,所以问题没有被发现。但是当您尝试让它变得有用时,您有两个选择:

  1. 比较字符串字段
  2. 比较 T成员(member)

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

关于带有通配符的 Java 泛型在 Eclipse 中编译,但在 javac 中不编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13534946/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com