加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Java 8类型推断导致在调用时省略泛型类型

发布时间:2020-12-15 02:17:34 所属栏目:Java 来源:网络整理
导读:升级到 Java 1.8后,我遇到了一个泛型方法的问题,这对于Java 1.6和1.7来说很好 请考虑以下代码: public class ExtraSortListE extends ArrayListE { ExtraSortList(E... elements) { super(Arrays.asList(elements)); } public ListE sortedCopy(Comparator?
升级到 Java 1.8后,我遇到了一个泛型方法的问题,这对于Java 1.6和1.7来说很好
请考虑以下代码:

public class ExtraSortList<E> extends ArrayList<E> {
    ExtraSortList(E... elements) {
        super(Arrays.asList(elements));
    }

    public List<E> sortedCopy(Comparator<? super E> c) {
        List<E> sorted = new ArrayList<E>(this);
        Collections.sort(sorted,c);
        return sorted;
    }

    public static void main(String[] args) {
        ExtraSortList<String> stringList = new ExtraSortList<>("foo","bar");

        Comparator<? super String> compGen = null;
        String firstGen = stringList.sortedCopy(compGen).get(0); // works fine

        Comparator compRaw = null;
        String firstRaw = stringList.sortedCopy(compRaw).get(0); // compiler ERROR: Type mismatch: cannot convert from Object to String
    }
}

我尝试使用Oracle javac(1.8.0_92)和Eclipse JDT(4.6.1)编译器.两者都是一样的结果. (错误消息有点不同,但基本相同)

除了事实,可以通过避免原始类型来防止错误,它让我困惑,因为我不明白原因.

为什么sortedCopy-Method的raw方法参数对返回值的泛型类型有任何影响?泛型类型已在类级别定义.该方法未定义单独的泛型类型.引用列表的类型为< String>,返回的List也应如此.

为什么Java 8会在返回值上丢弃类中的泛型类型?

编辑:如果sortedCopy的方法签名被更改(由biziclop指出)

public List<E> sortedCopy(Comparator c) {

那么编译器确实从类型ExtraSortList< E>中考虑通用类型E.并且不会出现错误.但是现在参数c是原始类型,因此编译器无法验证提供的Comparator的泛型类型.

编辑:我做了一些Java语言规范的评论,现在我想一想,我是否缺乏理解,或者这是编译器的一个缺陷.因为:

> Scope of a Declaration的泛型类型E是ExtraSortList类,它包括方法sortedCopy.
>方法sortedCopy本身不声明泛型类型变量,它只是从类范围引用类型变量E.见JLS中的Generic Methods
> JLS也在同一部分中说明

Type arguments may not need to be provided explicitly when a generic method is invoked,as they can often be inferred (§18 (Type Inference)).

>引用stringList是使用String定义的,因此编译器不需要在sortedCopy的调用中推断类型forE,因为它已经定义.
>因为stringList已经具有E的具体类型,所以参数c应该是Comparator<?超级字符串>对于给定的调用.
>返回类型也应该使用已经具体化的类型E,因此它应该是List< String>.

这是我目前对我认为Java编译器应如何评估调用的理解.如果我错了,解释为什么我的假设是错误的将是很好的.

解决方法

为了解决这个问题的最终答案:

就像@Jesper已经提到的那样,你不应该使用原始类型(特别是在多种情况下使用Generic作为类型).
由于您传递的是没有Generic-Type的Comparator,实际上没有.您可以将E-Generic视为null以使其更容易.因此,您的代码变为:

public List sortedCopy(Comparator c) {
    List sorted = new ArrayList(this);
    Collections.sort(sorted,c);
    return sorted;
}

现在你正在尝试/假设你从没有泛型的List中得到一个String,因此得到一个Object(因此它是所有东西的超类).

关于为什么raw-type参数对返回类型没有影响的问题,因为你没有指定某个抽象级别.例如,您必须定义Generic必须扩展/实现的类型,以至少实现这一点(编译错误).

public class ExtraSortList<E extends String> extends ArrayList<E> {

现在只允许扩展它的字符串或类(这里不可能,因为字符串是最终的).有了它,你的后备类型将是String.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读