Inner classes with the same name as an outer class?

前端 未结 5 1072
无人共我
无人共我 2020-12-17 17:44

Constraints:

I have a maven source code generator that I wrote that is creating POJO classes from some data files that have nested namespaces. I w

相关标签:
5条回答
  • 2020-12-17 18:15

    No. From the JLS section on class declarations:

    It is a compile-time error if a class has the same simple name as any of its enclosing classes or interfaces.

    Note: I somehow managed to miss this on my first pass through looking for an explicit rule. Check the edit history if you want the tortuous way I got here.

    0 讨论(0)
  • 2020-12-17 18:16

    You asked: Is there any trick to get this to compile?.

    The answer is: Well, maybe....

    Maze

    Create a class like the following:

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

    And a class where this class is going to be used

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

    Then, download the Apache Byte Code Engineering Library (BCEL), and create and run the following class:

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

    This uses the BCELifier class from the BCEL. This is a class that takes a .class file, and creates a .java file that can be compiled to a .class file, that, when it is executed, creates the .class file that it was originally fed with. (Side note: I love this library).

    So the A$B$XCreator.java file that is created there contains the BCEL code that is necessary to create the A$B$X.class file. This consists of statements like the generation of the constant pool and the instructions:

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

    Similarly, the AUseCreator.java contains the BCEL code that creates the AUse.class. For example, the instruction of the constructor invocation of `A$B$X':

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

    Now you can simply replace the String occurrences of "A$B$X" with "A$B$A" in the A$B$XCreator.java and AUseCreator.java, and then compile and run these classes.

    The result will be a A$B$A.class file, and a AUse.class file that uses the A$B$A.class. Executing the AUse will print

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

    I'm not sure whether this is considered as a "trick", or whether it still can be called "compiling" at all, but there is a way, at least. The key point is here, of course, that the fact that it did not compile is solely due to a limitation of the language, but there is no reason why this should not be representable in form of class files, regardless of how they are created.

    0 讨论(0)
  • 2020-12-17 18:19

    You can't get it to compile, but more importantly, why would you need to?

    What's wrong with:

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

    This seems like a design problem that you need to fix. If you can't rename it, consider anonymous inner classes. Or take some of those classes outside. Or just don't even use them.

    0 讨论(0)
  • 2020-12-17 18:27

    Depending on what you're after, the following might work for you:

    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());
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-17 18:29

    It's a bit of a hack, but this compiles at my machine:

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

    Try it. Literally: copy-past this thing ;)

    SPOILER:

    The name of the inner class is a capital letter alpha of the Greek alphabet. It's a Unicode character.

    0 讨论(0)
提交回复
热议问题