2

这个问题与上一个问题有关。可以通过添加强制转换来进行未经检查的转换来解决原始问题。所以现在我有以下代码:

import java.util.EnumSet;

class A {
    static enum E1 {
    X
    }

    private static <T extends Enum<T>> EnumSet<T> barEnum(Class<T> x) {
        return null;
    }

    private static void foo1(EnumSet<E1> s, E1 e) {
        EnumSet<E1> x2 = barEnum((Class<E1>)e.getClass());
    }

    private static void foo2(EnumSet<E1> s) {
        EnumSet<E1> x = barEnum((Class<E1>)s.iterator().next().getClass());
    }
}

我的初衷是写一个泛型方法。所以我将方法概括foo2()为:

private static <E extends Enum<E>> void foo3(EnumSet<E> s) {
    EnumSet<E> x = barEnum(s.iterator().next().getClass());
}

这显然包含未经检查的转换,并带有适当的警告进行编译。但我没有getClass()明确地将结果转换为Class<E>. 由于foo1()是泛型方法的一个实例foo3(),我预计我也需要在这里添加演员表。比较... foo1()_foo4()

    private static void foo4(EnumSet<E1> s) {
        EnumSet<E1> x = barEnum(s.iterator().next().getClass());
    }

...两者实际上相似(主要区别在于E1 e参数foo1())。然而foo1()编译,但foo4()不编译。我觉得这很矛盾。是否有任何规则允许对泛型方法进行隐式转换?

4

3 回答 3

2

有两件事发生。首先,如果您查看 javadoc,getClass它会说:

实际结果类型是Class<? extends |X|>在哪里擦除调用|X|的表达式的静态类型。getClass

这意味着在您的泛型方法中,使用 a而不是 abarEnum调用。由于是原始类型,这会创建一个未经检查的调用,这反过来意味着返回类型被删除(另请参阅:Why is generic of a generic of a return type when there is an unchecked conversion of a method parameter in Java 8?)。Class<? extends Enum>Class<? extends Enum<E>>Enum

因此,在这种情况下,barEnum实际上是返回 a EnumSet,这是一种原始类型,可以在未经检查的情况下转换为EnumSet<E>.

对于您的非泛型方法,您必须将参数显式转换为 a Class<E1>,因此方法参数没有未经检查的转换,因此没有未经检查的调用。但是,这也意味着返回类型不会被删除,编译器无法找到T对该调用有效的类型。

于 2018-01-31T10:49:33.550 回答
0

当我为获得的 Class 提取一个变量并让我的 IDE “修复”它所能做的一切时,我得到了这个:

private static void foo4(Iterable<E1> s) {
    Class<? extends E1> aClass = s.iterator().next().getClass();
    EnumSet<E1>         x      = barEnum(aClass);
}

如您所见,aClass未参数化(有警告Enum说它是“原始的”)。此外,它声明它可以是 Enum 的任何子类,而barEnum仅接受特定的枚举,并且由于特定的枚举是final类(它们不能有子类),因此存在冲突。

当我然后更改batEnum

private static <T extends Enum<T>> EnumSet<T> barEnum(Class<? extends T> x) {

错误消失了,因为它现在接受Enum.

于 2018-01-31T10:47:36.160 回答
0

我的建议是阅读优秀的 Java 泛型常见问题解答: http ://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html

在我的脑海中,它不会编译,因为静态方法不继承泛型类的类型参数。然后,您尝试获取参数化类型的运行时类信息,这将不起作用,因为 Java 对其泛型实现使用擦除。

一旦您超越了简单的集合等,Java 中的泛型就一点也不简单了。这就是为什么常见问题解答是不可或缺的资源。

于 2018-01-31T10:29:35.110 回答