为什么在泛型类上调用具有泛型返回的方法被javac认为是不安全的?

2022-09-03 06:51:56

请考虑以下代码:

public class Main {
    public static class NormalClass {
        public Class<Integer> method() {
            return Integer.class;
        }
    }

    public static class GenericClass<T> {
        public Class<Integer> method() {
            return Integer.class;
        }
    }

    public static void main(String... args) {
        NormalClass safeInstance = new NormalClass();
        Class<Integer> safeValue = safeInstance.method();

        GenericClass unsafeInstance = new GenericClass();
        Class<Integer> unsafeValue = unsafeInstance.method();
    }
}

如果我用以下公式编译它:

$ javac -Xlint:unchecked Main.java 

它返回:

Main.java:16: warning: [unchecked] unchecked conversion
        Class<Integer> unsafeValue = unsafeInstance.method();
                                                          ^
  required: Class<Integer>
  found:    Class
1 warning

请注意,只有泛型方法被认为是不安全的,即使返回类型上没有引用泛型类型。

这是一个错误吗?还是有更深层次的原因我没有考虑到这一点?javac


答案 1

允许原始类型以确保与引入泛型之前编写的代码兼容。原始类型的工作原理是简单地忽略所有方法参数和返回类型中的所有类型信息,甚至忽略与类的类型参数无关的类型信息。正如你所发现的那样,这可能会导致奇怪的结果。但它比这更奇怪。例如,这将编译。

public class Main {

    public static class GenericClass<T> {
        public void foo(Class<Integer> clazz) {
        }
    }

    public static void main(String... args) {
        GenericClass unsafeInstance = new GenericClass();
        unsafeInstance.foo(String.class);
    }
}

答案 2

未从其超类或超接口继承的原始类型 C 的构造函数 (§8.8)、实例方法 (§8.4、 §9.4) 或非静态字段 (§8.3) M 是原始类型,该类型对应于在对应于 C 的泛型声明中擦除其类型。

Java 语言规范


推荐