Java 中的泛型类型化内部类

2022-09-03 16:17:05

我学习和尝试Java泛型已经有一段时间了,但我遇到了一些我无法解释的事情。以以下代码为例:

public class Question {
    public <T> Sub<T> getSub(Class<T> c) {
        return new Sub<T>(c);
    }
    public class Sub<S> {
        private Class<S> c;
        public Sub(Class<S> c) {
            this.c = c;
        }
        public void add(S s) {
        }
    }
}

和测试代码:

import generics.Question.Sub;

public class Answer {
    public static void main(String [] args) {
        Question q = new Question();
        Sub<String> s = q.getSub(String.class);
        s.add("");
    }
}

当它运行时,它会给出一个非常神秘的错误消息:

C:\Answer.java:8: incompatible types
found   : generics.Question.Sub<java.lang.String>
required: generics.Question.Sub<java.lang.String>
        Sub<String> s = q.getSub(String.class);
1 error

现在,通过一些实验,我已经找到了如何防止编译器错误的方法。我可以使 Sub 类成为静态内部类,或者我需要将 Sub 类称为 Question.Sub<String>。我不能做的是解释为什么我需要这样做。

我已经阅读了一些关于泛型的Java文档,但没有一个涵盖这种特殊情况。

任何人都可以解释为什么代码在当前形式下是不兼容的类型?

-编辑-

仔细观察这一点,我可以看到我在 Netbeans 之外也得到了相同的行为。如果我的代码在以下结构中:

generics\
generics\Question.java
generics\Answer.java

当我一起编译文件时,我没有收到错误:

C:\>javac generics\Question.java generics\Answer.java

C:\>

但是,当我首先编译问题,然后编译答案时,我收到错误:

C:\>javac generics\Question.java

C:\>javac generics\Answer.java
generics\Answer.java:8: incompatible types
found   : generics.Question.Sub<java.lang.String>
required: generics.Question.Sub<java.lang.String>
        Sub<String> s = q.getSub(String.class);
                                ^
1 error

我听说过一些关于类型擦除的事情。在这种情况下,情况是否如此?


答案 1

类型擦除是泛型当前在 Java 中实现方式的属性。这意味着变量的类型仅在编译时已知,但在运行时则不然。因此,例如,在下面:

Map<String,String> map = new HashMap<String,String>();

然后编译器知道检查以字符串/字符串为基础放入的项目。但是,编译后的代码对 String,String 一无所知 - 您仍然可以使用错误的类型插入对象,例如:

Map other = (Map)map;
other.put(new Integer(3), new Double( 4.5 );

问题在于,编译后的代码在传入时不检查参数类型,运行时也不检查参数类型(因为类型信息已被擦除,因此类型擦除)。

我怀疑类型擦除在这里是一个问题 - 因为在编译时,你有完整的类型信息 - 但它可能是一个错误。泛型(来自实现)存在很多棘手的问题,并且JavaC和Eclipse使用不同的编译器,因此可能会表现出不同的错误。在某些情况下,Eclipse 编译器比 Sun 编译器更忠实于规范(因此 Eclipse 会产生错误,而 Sun 则不会),这主要是由于类型系统工作方式的复杂性。

因此,它很可能是1.5.0_14编译器中泛型的一个(或多个)错误...


答案 2

推荐