简体   繁体   中英

Why does instanceof seem to work in a static generic function sometimes?

Greetings. This is my first post in this site.

I thought that because of type erasure , one could not expect the following code to compile, and indeed, it did not compile on an earlier version of Eclipse. My understanding was that instanceof was a run-time operator and could not know about the generic type which would be, by run-time, compiled away:

   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");
   }

However, I was surprised to see that one of your threads actually included some code like this in an answer, and my latest Eclipse (Galileo on Windows with JVM 1.6 rev 20) is perfectly happy with it -- and it works, too. (I did notice that someone said it worked on Eclipse but not in another IDE/JDK in that thread, but don't remember the specifics.)

Can someone explain why it works, and more importantly, because I have to guide my students, whether it should be expected to work in the future.

Thank you. (I hope the code formatting comes through correctly - it looks indented correctly from my perspective and there are no tabs.)

What is erased is E . You can't, in fact, do if (e instanceof E) , because the type parameter E is erased. However, String is not a parameterized type, and e does have a run-time type, so if (e instanceof String) works just fine.

JLS 15.20.2 Type comparison instanceof operator

 RelationalExpression: RelationalExpression instanceof ReferenceType 

The type of a RelationalExpression operand of the instanceof operator must be a reference type or the null type; otherwise, a compile-time error occurs. The ReferenceType mentioned after the instanceof operator must denote a reference type; otherwise, a compile-time error occurs. It is a compile-time error if the ReferenceType mentioned after the instanceof operator does not denote a reifiable type (§4.7).

String is a reifiable type. E is not.

JLS 4.7 Reifiable Types

Because some type information is erased during compilation, not all types are available at run time. Types that are completely available at run time are known as reifiable types. A type is reifiable if and only if one of the following holds:

  • It refers to a non-generic type declaration.
  • It is a parameterized type in which all type arguments are unbounded wildcards
  • It is a raw type.
  • It is a primitive type.
  • It is an array type whose component type is reifiable.

See also

That works fine. The method that takes E e is compiled as Comparable e , but that doesn't prevent checks against types that exist at runtime ( String in your example). What you can't do is check for something like ArrayList<String> (or a generic specialization of your own class), because the ArrayList type exists at runtime, but ArrayList<String> does not. Thus, people use hacks like checking the first element of the list.

The lower case e is an object and every object has it's type. You can check instanceof on any object. Read your code with different names and it'll be easier to get:

   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");
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM