javagenericsinstanceof

How does instanceof with generics work in Java despite type erasure?


I've been under the impression that in Java, the instanceof operator cannot be used with generics due to type erasure. However, the first conditional statement in my code snippet below compiles and runs without any errors. Can anyone shed light on why the first conditional doesn't cause a compile-time error? I'm using IntelliJ IDEA with Oracle JDK 17.

public class InstanceofTest {
    public static class Tea {}
    public static class Herb {}

    // Why is this working?
    public static void main(String[] args) {
        List<Tea> teas = new ArrayList<>();

        if (teas instanceof List<Tea>) {
            System.out.println("TRUE");
        } else {
            System.out.println("FALSE");
        }

        // Compile error
        // if (teas instanceof List<Herb>) {
        //     System.out.println("TRUE");
        // } else {
        //     System.out.println("FALSE");
        // }
    }
}

Solution

  • In Java, generics like List<Tea>, are reduced to just List when your code runs, that's why you generally can't use instanceof with a generic type. The reason instanceof List<Tea> works is because, at compile time, the Java compiler is only checking against the List part of List<Tea>. It doesn't care about the <Tea> part because of type erasure, but it doesn't throw an error since it's not wrong to write it that way, and the syntax itself isn't incorrect. The compiler is aware that you're dealing with a List<Tea> from the context, so it won't object.

    On the other hand, when you try instanceof List<Herb>, the compiler steps in because it knows your list can't be a List<Herb>, since you told it it was a List<Tea>. This happens at compile time, based on the information you've provided, regardless of the list's actual content at runtime.

    TL;DR:
    Java compiler makes decisions based on the information available at compile time, not on the actual contents of the list during runtime, due to type erasure.