你问道:
有没有什么技巧可以让这个编译通过?
答案是:也许有……
创建一个类如下所示:
public class A
{
public class B
{
public class X
{
}
}
}
还有一个使用这个类的类
public class AUse
{
public static void main(String[] args)
{
A.B.X aba = new A().new B().new X();
System.out.println("Created "+aba+" of class "+aba.getClass());
}
}
然后,下载
Apache字节码工程库(BCEL),并创建并运行以下类:
import java.io.FileOutputStream;
import org.apache.bcel.Repository;
import org.apache.bcel.util.BCELifier;
public class CreateCreators
{
public static void main(String[] args) throws Exception
{
new BCELifier(
Repository.lookupClass("A"),
new FileOutputStream("ACreator.java")).start();
new BCELifier(
Repository.lookupClass("A$B"),
new FileOutputStream("A$BCreator.java")).start();
new BCELifier(
Repository.lookupClass("A$B$X"),
new FileOutputStream("A$B$XCreator.java")).start();
new BCELifier(
Repository.lookupClass("AUse"),
new FileOutputStream("AUseCreator.java")).start();
}
}
这里使用了BCEL中的BCELifier
类。这是一个类,它接受一个.class
文件,并创建一个.java
文件,可以编译成一个.class
文件。当它被执行时,它会创建最初提供的.class
文件。 (顺便说一句:我喜欢这个库)。
因此,创建的A$B$XCreator.java
文件包含了创建A$B$X.class
文件所必需的BCEL代码。这包括生成常量池和指令的语句:
...
_cg = new ClassGen("A$B$X", "java.lang.Object", "A.java",
ACC_PUBLIC | ACC_SUPER, new String[] { });
...
il.append(_factory.createFieldAccess("A$B$X", "this$1",
new ObjectType("A$B"), Constants.PUTFIELD));
同样地,
AUseCreator.java
包含创建
AUse.class
的BCEL代码。例如,在`A$B$X'的构造函数调用指令中:
...
il.append(_factory.createInvoke("A$B$X", "<init>", Type.VOID,
new Type[] { new ObjectType("A$B") }, Constants.INVOKESPECIAL));
现在,您只需要在
A$B$XCreator.java
和
AUseCreator.java
中简单地将字符串出现的
"A$B$X"
替换为
"A$B$A"
,然后编译并运行这些类。
结果将是一个
A$B$A.class
文件和一个使用
A$B$A.class
的
AUse.class
文件。执行
AUse
将会打印:
Created A$B$A@15f5897 of class class A$B$A
我不确定这是否被认为是一种“技巧”,或者它是否仍然可以被称为“编译”,但至少有一种方法。当然,关键点在于它无法编译仅仅是由于语言的限制,但无论如何,这应该可以以class
文件的形式表示,而不管它们是如何创建的。