views:

87

answers:

3

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.)

+3  A: 

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.

Matthew Flaschen
I see. Good to know, and thanks. A slightly older Eclipse, 3.2, for some reason didn't like even that (what I posted), so I wondered if there was some newfangled hanky panky going on in the newer version. The old error was something like "can't use an E and a String with instanceof". I should have saved it, but I no longer have that one installed. Anyway, much appreciated.
michael
+4  A: 

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

polygenelubricants
+2  A: 

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");
   }
Felipe Cypriano
That makes perfect sense. I do wonder why the code was failing in the earlier compiler. I did dummy down my code to make the question easy to understand, so its possible it was objecting to something else. But my original did work fine on Galileo / JVM 1.6 but not Eclipese 3.2 / JVM 1.6 and both compilers had 1.6 runtime selected. But your explanation was super clean, and thanks.
michael