与外部类同名的内部类?

2022-09-04 07:48:42

约束:

我有一个我写的maven源代码生成器,它正在从一些具有嵌套命名空间的数据文件创建POJO类。我希望每个命名空间都嵌套为一个内部类。在某些情况下,在我的控制之外,我最终会得到与最外层类相同的简单名称的内部类。

所有类都必须是作用域,因为这适用于属性文件之类的东西上的类型安全包装器,但具有层次结构。public

我无法更改名称,否则我将更改名称含义和包含数据的命名空间。

给定比我有以下代码:

public class A
{
    public class B
    {
        public class A
        {

        }
    }
}

内部类应该附加外部类的名称以形成一个唯一的命名空间,例如,我还没有找到一个有效的理由来不编译它。A$B$A.class

有什么技巧可以编译它吗?


答案 1

来自 JLS 关于类声明的部分:

如果一个类与其任何封闭类或接口具有相同的简单名称,则这是一个编译时错误。

注意:我不知何故设法在我第一次通过寻找明确的规则时错过了这一点。检查编辑历史记录,如果你想要曲折的方式,我在这里。


答案 2

你问:有什么诀窍可以让它编译吗?

答案是:嗯,也许....

Maze

创建如下所示的类:

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

因此,在此处创建的文件包含创建该文件所需的 BCEL 代码。这由常量池的生成和指令等语句组成:A$B$XCreator.javaA$B$X.class

...
_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));

同样,包含创建 .例如,构造函数调用 'A$B$X' 的指令:AUseCreator.javaAUse.class

...
il.append(_factory.createInvoke("A$B$X", "<init>", Type.VOID, 
    new Type[] { new ObjectType("A$B") }, Constants.INVOKESPECIAL));

现在,您只需将 和 中的 String 实例替换为 ,然后编译并运行这些类。"A$B$X""A$B$A"A$B$XCreator.javaAUseCreator.java

结果将是一个文件,以及一个使用 .执行遗嘱打印A$B$A.classAUse.classA$B$A.classAUse

Created A$B$A@15f5897 of class class A$B$A

我不确定这是否被认为是一种“技巧”,或者它是否仍然可以被称为“编译”,但至少有一种方法。当然,关键点是,它没有编译的事实仅仅是由于语言的限制,但是没有理由为什么它不应该以文件的形式表示,无论它们是如何创建的。class


推荐