为什么“t instanceof T”不允许,其中T是类型参数而t是变量?

时间:2012-01-05 11:47:49

标签: java generics instanceof type-parameter

Eclipse表示由于通用类型橡皮擦,类型参数不允许使用instanceof操作。

我同意在运行时,没有类型信息。但请考虑以下类的通用声明:

class SomeClass<T>{
    T t;
    SomeClass(Object o){
        System.out.println(o instanceof T);   // Illegal
    }   
}        

在运行时,不会出现T!但是如果我实例化这个类型为Integer的类,那么相应的对象将有一个Integer类型的字段。

然后,为什么我不能用T检查变量的类型,它可以在运行时由Integer替换。我实际上会做“o instanceof Integer”这样的事情。

在哪些情况下,允许带有类型参数的instanceof会导致麻烦,以致它被禁止?

7 个答案:

答案 0 :(得分:5)

如果在运行时需要T,则需要在运行时提供它。这通常通过传递Class&lt; T&gt;来完成。 T必须是。

class SomeClass<T> {
    final T t;

    public SomeClass(Class<T> tClass, T t) {
        if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass);
        this.t = t;
    }

    private SomeClass(T t) {
        this.t = t;
    }

    public static <T> SomeClass<T> of(Class<T> tClass, T t) {
        if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass);
        return new SomeClass(t);
    }
} 

// doesn't compile
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, "one");

Class clazz = Integer.class;
// compiles with a warning and throws an IAE at runtime.
SomeClass<Integer> intSomeClass = (SomeClass<Integer>) SomeClass.of(clazz, "one");

// compiles and runs ok.
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, 1);

答案 1 :(得分:5)

  

但是如果我实例化这个类的Integer类型,那么   相应的对象将具有Integer类型的字段t

不,它不会。它将具有Object类型的字段。只要每次访问它,它都会被转换为Integer。

请考虑以下代码:

SomeClass<Integer> c = new SomeClass<Integer>();
SomeClass untyped = (SomeClass)c; // Which type was it?
SomeClass<String> stringTyped = (SomeClass<String>)untyped; // Now it's STRING??

作品。给你一堆编译器警告,但有效。因为字段T实际上是Object类型,可以转换为任何东西。

答案 2 :(得分:3)

编译语句o instanceof T之后将是o instanceof Object,并且因为所有类型都派生自Object,所以它总是会计算为true。允许这种测试会产生假阳性结果

答案 3 :(得分:2)

由于type erasure,这永远不会奏效。在运行时,您只知道您的类具有类型参数T,但不知道它对于给定实例的类型。因此,您无法确定某个对象的类型是T,因为您不知道T是什么,而不是因为它会导致某种麻烦。

如果您需要执行此类运行时检查,请将类型标记明确传递给您的对象:

SomeClass(Object o, Class<T> type) {
    System.out.println(type.isInstance(o));
}

答案 4 :(得分:1)

  

但是如果我实例化这个类型为Integer的类,那么相应的对象将有一个Integer类型的字段。

实际上,它不会。它的字段t的类型为Object。正如您所说,泛型几乎完全是语法糖(例外情况是当您扩展泛型类并指定类型参数时,类型仍然是类文件中的元数据)。

答案 5 :(得分:0)

泛型类型参数在运行时是未知的,因此没有可以比较的类。 T仅在编译时已知。泛型只会帮助开发人员更轻松地编写代码。但在运行时,参数只是Object个实例。

答案 6 :(得分:0)

Java使用“Erasure”实现其Generics,它可以检查类型并删除“ COMPILE TIME ”中的类型参数信息,在“ RUN TIME ”中会有只有类型参数的 BOUNDARIES ,所以不会出现像“整数”这样的东西