使用本地 类 时出错 "illegal generic type for instanceof"

Error "illegal generic type for instanceof" when using local classes

我有以下 Java 使用 local class.

的代码
import java.util.Arrays;

public class X<T> {
    void m() {
        class Z {}

        for (Object o : Arrays.asList(1, 2, 3))
            if (o instanceof Z) {}
    }
}

它没有编译并出现以下错误消息:

X.java:8: error: illegal generic type for instanceof
            if (o instanceof Z) {}
                             ^
1 error

我了解到本地 class Z 继承了 X<T> 的通用类型签名,是一个内部 class。同样的编译错误出现在这个例子中,其中 Z 不是本地的,但仍然是 inner:

import java.util.Arrays;

public class X<T> {
    class Z {}

    void m() {
        for (Object o : Arrays.asList(1, 2, 3))
            if (o instanceof Z) {} // Compilation error
    }
}

可以通过使 Z 非内部/静态来解决:

import java.util.Arrays;

public class X<T> {
    static class Z {}

    void m() {
        for (Object o : Arrays.asList(1, 2, 3))
            if (o instanceof Z) {} // Compiles now
    }
}

或通过qualifying X.Z:

import java.util.Arrays;

public class X<T> {
    class Z {}

    void m() {
        for (Object o : Arrays.asList(1, 2, 3)) {
            if (o instanceof X.Z) {}    // Compiles now
            if (o instanceof X<?>.Z) {} // Also
        }
    }
}

但是我如何才能限定本地 class,或者在不更改本地 class 本身的情况下解决此限制?

一种可能的解决方法是使用反射:

import java.util.Arrays;

public class X<T> {
    void m() {
        class Z {}

        for (Object o : Arrays.asList(1, 2, 3))
            if (Z.class.isInstance(o)) {}
    }
}

这也应该有效。也使用反射。但似乎是一个有效的解决方案。

import java.util.Arrays;

public class X<T> {


    void m() {

        class Z2 {
        }

        for(Object o: Arrays.asList(1,2,3)) {
            if(Z2.class.isAssignableFrom(o.getClass())) {

            }
        }

    }

}

显然,通过使 Z 泛型编译成功。我预计需要 <T> 作为类型参数,但你只需要把它变成通用的,所以什么都可以

import java.util.Arrays;

public class X<T> {
    void m() {
        class Z<Anything> {}

        for (Object o : Arrays.asList(1, 2, 3))
            if (Z.class.isInstance(o)) {}
    }
}

正确的解决方案是限定本地 class,但我认为您做不到。要么将其重构为私有静态 class,要么这可能是您可以获得的最好结果。

对我来说,这似乎是 Java 语言的疏忽或限制,我认为这是不可能的。

根据 JLS 4.7, meaning that it must be expressed as a reifiable type by its fully qualified name. At the same time, JLS 6.7 声明,instanceof 表达式中的引用类型必须是可具体化的,因为本地 classes 没有完全限定的名称,因此它们不能表示为具体化。

如果您将 Z 声明为泛型,则 instanceof 运算符会将 Z 视为原始类型,其中它的所有泛型属性(在本例中为封闭的 class)都被视为原始类型以及。 (类似于原始类型的泛型方法被认为是原始的,尽管有任何泛型签名。这是一种保持类型泛化向后兼容性的措施。)由于任何原始类型都是可具体化的,因此将 Z 声明为泛型将编译。