Hakanai
Hakanai

Reputation: 12680

Why can't I have a two-level-deep inner class with the same name as its containing class?

Today, some other developer found an XML schema with some interesting nesting, which JAXB compiled into a structure like this:

public class Choices
{
    public static class Choice
    {
        public static class Choice
        {
        }
    }
}

If you try to compile this, the Java compiler says,

class Choices.Choice is already defined in class Choices

with of course, the underline on the innermost class Choice declaration.

But I say, class Choices.Choice is not what it was trying to declare. Rather, it was trying to declare Choices.Choice.Choice, which would be a different class.

Interestingly, this is fine:

public class OuterClass
{
    public static class Inner1
    {
        public static class Inner2
        {
        }
    }

    public static class Inner2
    {
        public static class Inner1
        {
        }
    }
}

But this is banned:

public class OuterClass
{
    public static class Inner1
    {
        public static class Inner2
        {
            public static class Inner1
            {
            }
        }
    }
}

So I guess the rule is that the name of a class can't be the same as a containing class at any level. Obviously the fix here is already known- get JAXB not to generate invalid code.

But my question is, why is this restriction even present? What is the Java compiler trying to avoid by not letting us create an inner class with the same name as a containing class?

Upvotes: 8

Views: 638

Answers (2)

The Vanguardian
The Vanguardian

Reputation: 21

Create a complexType,then refer to the 2nd level (of same name). Use a different name, this will create a different class and satisfy java requirements.

i.e.

Choices = Choices.class
Choice = Choice.class
Choice(2nd level) = InnerChoice.class

<complexType name = "innerChoice" >
  <sequence>
    .....
  </sequence>
</complexType>

 <element name="choices">
   <complexType>
     <sequence>
       <element name="choice">
         <complexType>
           <sequence>
             <!-- NEW! -->
             <element name="choice"  type="innerChoice">
             <!- This used to say 
             <element name="choice">
               <complextype>
                <sequence>
                  ....
                </sequence>
               </complexType>
             -->
          .....

Now your generated class files will be Choices.Choice.InnerChoice which will be assigned to variable choice (variable names can be nested ok, not class names)

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726609

Java lets you refer to an outer class without fully specifying its name, like this:

public static class Inner1
{
    public static class Inner2
    {
        public static class Inner3
        {
            public void demo() {
                Class<Inner2> c = Inner2.class; // This is allowed
            }
        }
    }
}

Had nesting of classes allowed the use of identical names at any level of hierarchy, referencing by unqualified name would have been impossible. It is this ability that the Java compiler is trying to preserve by prohibiting nested declarations to collide with names of their outer classes.

Upvotes: 6

Related Questions