¿Clases internas con el mismo nombre que una clase exterior?

Restricciones:

Tengo un generador de código fuente de Maven que escribí que está creando clases de POJO a partir de algunos archivos de datos que tienen espacios de nombres nesteds. Quiero que cada espacio de nombres se anide como una clase interna. En algunos casos fuera de mi control, termino con clases internas que son del mismo nombre simple que la clase más externa.

Todas las clases deben ser de scope public ya que se trata de un contenedor tipo seguro sobre algo así como un archivo de propiedades, pero jerárquico.

No puedo cambiar los nombres; de lo contrario, estoy cambiando el significado de los nombres y el espacio de nombres que está adjuntando los datos.

Dado que tengo el siguiente código:

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

Las clases internas deben agregar el nombre de la clase externa para formar un espacio de nombres único, como A$B$A.class , no he encontrado una razón válida para no comstackr.

¿Hay algún truco para conseguir que esto compile?

No. De la sección JLS sobre declaraciones de clase:

Es un error en tiempo de comstackción si una clase tiene el mismo nombre simple que cualquiera de sus clases o interfaces adjuntas.

Nota: de alguna manera logré perderme esto en mi primer paso al buscar una regla explícita. Revisa el historial de edición si quieres la forma tortuosa que tengo aquí.

Usted preguntó: ¿Hay algún truco para hacer que esto se compile? .

La respuesta es: Bueno, tal vez …

Laberinto

Crea una clase como la siguiente:

 public class A { public class B { public class X { } } } 

Y una clase donde esta clase va a ser usada.

 public class AUse { public static void main(String[] args) { ABX aba = new A().new B().new X(); System.out.println("Created "+aba+" of class "+aba.getClass()); } } 

A continuación, descargue la Biblioteca de ingeniería de código de Apache Byte (BCEL) y cree y ejecute la siguiente clase:

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

Esto utiliza la clase BCELifier del BCEL. Esta es una clase que toma un archivo .class y crea un archivo .java que se puede comstackr en un archivo .class , que, cuando se ejecuta, crea el archivo .class el que se alimentó originalmente. (Nota al margen: me encanta esta biblioteca).

Así que el archivo A$B$XCreator.java que se crea allí contiene el código BCEL que es necesario para crear el archivo A$B$X.class . Esto consiste en declaraciones como la generación del conjunto constante y las instrucciones:

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

Del mismo modo, AUseCreator.java contiene el código BCEL que crea AUse.class . Por ejemplo, la instrucción de la invocación del constructor de `A $ B $ X ‘:

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

Ahora puede simplemente reemplazar las apariciones de String de "A$B$X" por "A$B$A" en A$B$XCreator.java y AUseCreator.java , y luego comstackr y ejecutar estas clases.

El resultado será un archivo A$B$A.class y un archivo AUse.class que usa la A$B$A.class AUse imprimirá la ejecución de AUse

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

No estoy seguro de si esto se considera como un “truco”, o si todavía se puede llamar “comstackción” en absoluto, pero hay una manera, al menos. El punto clave es aquí, por supuesto, que el hecho de que no se compiló se debe únicamente a una limitación del idioma , pero no hay razón para que esto no se pueda representar en forma de archivos de class , independientemente de cómo se creen. .

No puedes comstackrlo, pero lo que es más importante, ¿por qué lo necesitarías ?

Qué hay de malo en:

 public class A { public class B { public class InnerA { } } } 

Esto parece ser un problema de diseño que necesitas arreglar. Si no puede renombrarlo, considere clases internas anónimas. O toma algunas de esas clases afuera. O simplemente no los uses.

Es un poco pirateado, pero esto se comstack en mi máquina:

 class A { public class B { public class Α { } } } 

Intentalo. Literalmente: copiar-más allá de esta cosa;)

SPOILER:

El nombre de la clase interna es una letra mayúscula alfa del alfabeto griego. Es un personaje de Unicode.

Dependiendo de lo que estés buscando, lo siguiente podría funcionar para ti:

 public class A { class B extends C { } public static void main(String[] args) { new A().new B().new A(); } } class C { class A { { System.out.println(getClass()); } } }