【问题标题】:Error "illegal generic type for instanceof" when using local classes使用本地类时出现“instanceof 的非法泛型类型”错误
【发布时间】:2019-04-16 08:35:37
【问题描述】:

我有以下使用 本地类的 Java 代码。

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

我知道本地类Z 继承了X&lt;T&gt; 的泛型类型签名,是一个内部类。这个例子中出现了同样的编译错误,其中Z不是本地的,而是内部的:

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
        }
    }
}

但是我怎样才能在不改变本地类本身的情况下限定本地类,或者解决这个限制呢?

【问题讨论】:

  • 我认为这是一种编译器病态。这是告诉您类型不可具体化的一种奇怪方式。在 Eclipse 中情况更糟——它告诉你“使用 Z 形式”。
  • @RealSkeptic:Eclipse 的编译器消息在这里只是“不走运”。这通常是有用的额外信息。
  • 由此推论Z[] array = new Z[0]; 也是非法的。

标签: java generics local-class


【解决方案1】:

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

instanceof 表达式中的引用类型必须根据JLS 4.7 可具体化,这意味着它必须通过其完全限定名称表示为可具体化类型。同时,JLS 6.7 指出本地类没有完全限定的名称,因此它们不能表示为可具体化。

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

【讨论】:

  • 这是真的,但奇怪的是,如果 Z 本身是通用的,它确实允许它,尽管事实上你没有办法限定它。
  • "oversight" - 你是来和 JLS 设计师打架的,对吧? :)
  • 泛型已被修补到语言中,并且存在一些极端情况,例如未正确覆盖的类文字。没有什么是完美的,我认为有一个疏忽的机会。 ;)
  • 我扩展了我的答案来解释为什么泛型 Z 会起作用。
  • @LukasEder 我认为监督是正确的。有点像this question:这些案例本来可以设计出来的,但它们没有;我不判断他们是否应该
【解决方案2】:

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

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)) {}
    }
}

【讨论】:

    【解决方案3】:

    显然,通过使 Z 泛型编译成功。我预计需要 &lt;T&gt; 作为类型参数,但您只需将其设为通用,所以任何事情都可以

    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)) {}
        }
    }
    

    正确的解决方案是使本地课程合格,但我认为您不能。要么将它重构为私有静态类,要么这可能是你能得到的最好的。

    【讨论】:

    • 一旦您将Z 设为通用,您就无需再应用反射解决方法...
    【解决方案4】:

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

    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())) {
    
                }
            }
    
        }
    
    }
    

    【讨论】:

    • 我没有投反对票,但我想这是因为这里有更好的反射方式,正如我提到的in my own answer
    猜你喜欢
    • 2010-12-26
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 2022-11-07
    • 2021-02-16
    • 1970-01-01
    相关资源
    最近更新 更多