为什么我会得到“非法泛型类型”?

时间:2010-10-23 00:56:01

标签: java generics

假设:

public class C<T> {
    private class D {
        public boolean equals( Object o ) {
            if ( !(o instanceof D) )    // line 4
                return false;
            D other = (D)o;             // line 6
            return i == other.i;
        }
        int i;
    }
}

我明白了:

C.java:4: illegal generic type for instanceof
          if ( !(o instanceof D) )
                              ^

我还得到关于第6行的“未经检查的演员”警告。为什么? o 是泛型类型 - 它只是普通的Object。如何通过检查和转换为equals()的实例来正确实现D

注意:显然,此代码示例是我实际代码的缩减版本。 CD的真实类要大得多,Dprivate内部类C的实现。

仅供参考:真正的D确实使用了通用参数T

4 个答案:

答案 0 :(得分:37)

  

o不是泛型类型 - 它只是一个普通的对象。

这不是问题。问题......以及编译错误的根本原因...... D是一个泛型类。它是通用的,因为它是泛型类中的非静态嵌套类。其完全限定名称为some.pkg.C<T>.D

  

仅供参考:真正的D确实使用了通用参数T.

可以使用T这一事实使D成为通用类。

您无法使用instanceof D(D)的原因是泛型类型擦除。基本上,运行时无法区分(例如)C<String>.DC<Integer>.D的类型。由于它无法做到这一点,因此无法确定instanceof D是返回true还是false还是(D)应该成功还是抛出ClassCastException

一种解决方案是将D声明为静态。但这不适用于你的“真正的D”,因为静态类不能使用封闭类中的泛型类型参数。你的“FYI”说它就是这样。

另一种解决方案是实例化外部类C,将实际类型的T作为java.lang.Class<T>实例传递给它。然后使用此Class实例根据需要实现运行时类型检查和强制转换。这可能很麻烦。

第三个解决方案是仔细分析代码,并确定@SuppressWarning注释是否安全,以抑制“不安全的强制转换”等警告。

  

什么类型的擦除? 'o'直接是Object类型。

实际上Objecto变量的声明的类型。实际对象很可能具有其他类型, 类型(例如,如果它是D实例)将遭受类型擦除。

答案 1 :(得分:7)

如果使内部类静态,则代码编译得很好。

例如:

private static class D{...}

阅读here了解差异。

您也可以尝试o.getClass() != D.class(当然,在防止o为null之后)

答案 2 :(得分:7)

@StephenC是正确的,问题是D表示C<T>.D,这是一个参数化类型。解决方案是使用原始类型或通配符参数化类型:

if ( !(o instanceof C.D) )

if ( !(o instanceof C<?>.D) )

答案 3 :(得分:5)

D.class.isInstance(o)

似乎在这里工作。