Luk*_*der 61 java generics local-class
我有以下使用本地类的 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) {}
}
}
Run Code Online (Sandbox Code Playgroud)
它不会与以下错误消息一起编译:
X.java:8: error: illegal generic type for instanceof
if (o instanceof Z) {}
^
1 error
Run Code Online (Sandbox Code Playgroud)
我了解到,本地类Z
继承了的通用类型签名X<T>
,即内部类。在此示例中,出现了相同类型的编译错误,该错误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
}
}
Run Code Online (Sandbox Code Playgroud)
可以通过使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
}
}
Run Code Online (Sandbox Code Playgroud)
或通过排位赛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
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如何在不更改本地班级本身的情况下限定本地班级或解决此限制?
Raf*_*ter 43
对我来说,这似乎是Java语言的疏忽或限制,我认为这是不可能的。
instanceof
表达式中的引用类型必须根据JLS 4.7是可验证的,这意味着必须通过其完全限定的名称将其表示为可验证的类型。同时,JLS 6.7声明本地类没有完全限定的名称,因此不能将它们表示为可验证的。
如果将Z声明为泛型,则instanceof
运算符会将Z
其所有泛型属性(在本例中为封闭类)也视为原始类型,并将其视为原始类型。(类似于原始类型的泛型方法,尽管有任何泛型签名也被视为原始类型。这是一种保持类型生成向后兼容的措施。)由于任何原始类型都是可修正的,因此将Z声明为泛型即可编译。
Luk*_*der 28
可能的解决方法是使用反射:
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)) {}
}
}
Run Code Online (Sandbox Code Playgroud)
显然,通过使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)) {}
}
}
Run Code Online (Sandbox Code Playgroud)
正确的解决方案将使本地课程合格,但我认为您不能。您可以将其重构为私有静态类,或者可能是最好的。