为什么instanceof有时似乎在静态泛型函数中工作?

时间:2010-05-08 02:44:00

标签: java static methods generics instanceof

问候。这是我在这个网站上的第一篇文章。

我认为由于 类型擦除 ,人们不能指望编译以下代码,事实上,它不能在早期版本的Eclipse上编译。我的理解是 instanceof 是一个运行时操作符,无法知道通过运行时编译的泛型类型:

   public static <E extends Comparable<? super E>> 
   void SampleForQuestion(E e)
   {
      if ( !(e instanceof String) )
         System.out.println("I am not a String");
      else
         System.out.println("I am  a String");
   }

然而,我很惊讶地看到你的一个线程实际上在答案中包含了这样的代码,而我最新的Eclipse(Windows上的Galileo和JVM 1.6 rev 20)对它非常满意 - 并且它有效,太。 (我注意到有人说它在Eclipse上工作但在该线程的另一个IDE / JDK中没有,但是不记得具体细节。)

有人可以解释它为什么有效,更重要的是,因为我必须引导我的学生,是否应该预期它将来有用。

谢谢。 (我希望代码格式化正确 - 从我的角度来看它看起来是正确缩进的,并且没有标签。)

3 个答案:

答案 0 :(得分:4)

删除的内容是E。事实上,您不能if (e instanceof E),因为类型参数E已被删除。但是,String不是参数化类型,而e确实具有运行时类型,因此if (e instanceof String)工作正常。

JLS 15.20.2 Type comparison instanceof operator

RelationalExpression:
    RelationalExpression instanceof ReferenceType
     

RelationalExpression运算符的instanceof操作数的类型必须是引用类型或null类型;否则,发生编译时错误。 ReferenceType运算符后面提到的instanceof必须表示引用类型;否则,发生编译时错误。 如果在 ReferenceType 运算符后面提到的 instanceof 不表示可再生类型,则为编译时错误(§4.7)。

String是一种可重复的类型。 E不是。

JLS 4.7 Reifiable Types

  

由于在编译期间会删除某些类型信息,因此并非所有类型在运行时都可用。在运行时完全可用的类型称为可重新类型。当且仅当下列之一成立时,类型才可以恢复:

     
      
  • 它指的是非泛型类型声明。
  •   
  • 这是一个参数化类型,其中所有类型参数都是无界通配符
  •   
  • 这是一种原始类型。
  •   
  • 这是一种原始类型。
  •   
  • 这是一种数组类型,其组件类型可以恢复。
  •   

另见

答案 1 :(得分:3)

工作正常。将E e的方法编译为Comparable e,但这不会阻止对运行时存在的类型(在您的示例中为String)进行检查。您不能做的是检查类似ArrayList<String>(或您自己类的通用特化)的内容,因为ArrayList类型在运行时存在,但ArrayList<String>不存在。因此,人们使用黑客来检查列表的第一个元素。

答案 2 :(得分:2)

小写e是一个对象,每个对象都有它的类型。您可以检查任何对象上的instanceof。阅读具有不同名称的代码,这将更容易获得:

   public static <E extends Comparable<? super E>> 
   void SampleForQuestion(E paramObject)
   {
      if ( !(paramObject instanceof String) )
         System.out.println("I am not a String");
      else
         System.out.println("I am  a String");
   }