2

In the code extracted from Java Complete Reference by Herbert Schildt:

class Gen<T> {
  T obj;

  Gen(T o) {
    ob = o;
  }

  T getob() {
    return ob; 
  }
}

class Gen2<T> extends Gen<T> {
  Gen2(T o) {
    super(o);
  }
}

class Test {
  public static void main(String args[]) {
    Gen2<Integer> obj = new Gen2<Integer>(99);
  }
}

he mentions that instanceof can't verify if a object is from a typed generic class at runtime because no Generic information is available:

if (obj instanceof Gen2<Integer>) // illegal, doesn't compile

you can only use

if (obj instanceof Gen2<?>) // legal

However, you can still Cast the same object to (Gen) as long as it is compatible:

(Gen<Integer>) obj // legal

but:

(Gen<Long>) obj // illegal

Isn't this a Java contradiction? If Java knows that obj can be cast to a Gen at runtime, why doesn't it knows that obj is an instanceof Gen class/subclass?

  • "`(Gen) obj // illegal`" out of context, it isn't clear why this one is illegal, but the other is allowed. But the general answer is "because of type erasure". – Andy Turner Dec 15 '17 at 14:44
  • I do understand why type erasure makes instanceof an illegal call (erasure automatically removes Generic information and makes all castings from Object to type transparent), but I don't understand why it doesn't affect Casting. That was my question. –  Dec 15 '17 at 14:48
  • Like I say, it's not possible to say why the first cast is legal but the second one is illegal based on the information you have provided. If `obj` is an `Object`, and the type variable is unbounded, either of them would be legal; if it's something more specific, as implied by bounds on the type declaration, that's down to the way they're declared, and you'd need to show the declarations to say the specific reason. Please [edit] your question to show a [mcve]. – Andy Turner Dec 15 '17 at 14:51
  • I've added the related code from the book. Didn't mention before but while the duplicated link explains the first part, it doesn't explain why then the Casting to Gen works but to Gen doesn't (in fact, the original answer don't even mention Casting). Now that I provided the complete example, can you elaborate on your answer to include an explanation for Casting? –  Dec 15 '17 at 15:08
  • That's because the compiler knows that you've got a `Gen2`, so it can never by a `Get2`, in the same way that a `List` can never be a `List`. – Andy Turner Dec 15 '17 at 15:14
  • 5
    The difference here is that `instanceof` is evaluated at runtime, and thus it only makes sense to accept a reifiable type as the second operand, since that's all you'll be able to test. However, the casting to `Gen` is being checked at compile time: the compiler knows this can never be safe. You can trick it, by casting twice: `(Gen) (Gen>) obj`; but that's not safe. – Andy Turner Dec 15 '17 at 15:18
  • `Object o = new ArrayList(); ((ArrayList) o).add(1);` is not "illegal" as such; it's just wrong. – Klitos Kyriacou Dec 15 '17 at 17:48

1 Answers1

-1

I read the book, confused by this too, I found this, maybe helpful: https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#cannotCast

However, in some cases the compiler knows that a type parameter is always valid and allows the cast. For example:

List<String> list1 = ...;
ArrayList<String> list2 = (ArrayList<String>)list1;  // OK
martijnn2008
  • 3,552
  • 5
  • 30
  • 40
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/20129903) – Vikas Jun 26 '18 at 17:20
  • @Vikas the original answer did include enough of the content. – Pat Jun 26 '18 at 17:32