javastatic-methodsinner-classesstatic-classes

My static method can't find my static inner class' static inner class


I tried to run the following code contained in my MainClass.java file, but it failed with a compilation error.

public class MainClass
{

   public static interface StaticParentType{
      public static class StaticChildType implements StaticParentType {}
   }

   public static void main(final String[] args)
   {
      new StaticChildType();
   }

}

It failed with the following compilation error.

$ java MainClass.java
MainClass.java:10: error: cannot find symbol
      new StaticChildType();
          ^
  symbol:   class StaticChildType
  location: class MainClass
1 error
error: compilation failed

I tried various different combinations of public/private, static/non-static, and it seems the only way to get my code to work is to do something like the following instead.

public class MainClass
{

   public static interface StaticParentType{}
   public static class StaticChildType implements StaticParentType {}


   public static void main(final String[] args)
   {
      new StaticChildType();
   }

}

So, I am not blocked, I have a decent enough workaround here. It seems that having the class contained within the curly braces prevents the main method from being able to see and/or use it.

My question is why? More specifically, why would a public static inner class be invisible to the main method? I really felt like being public and static (as well as the interface being public and static) would make it visible, but it appears not. I spent a couple minutes searching StackOverflow and the internet, but it didn't seem to come up.


Solution

  • Funnily enough, when adding the tags for this question, the resources for inner-classes and static-classes pointed me in the right direction.

    For starters, part of the reason I couldn't find my answer was because I was using the wrong terminology. As it turns out, the official word for it is static nested class, which you can see over here (Ctrl+F "Terminology") -- https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

    As it turns out, if you want to use a static nested class outside of the class that is nesting it, you must refer to the static nested class like this.

    StaticParentType.StaticChildType

    PLEASE NOTE, this syntax is only if my nested class is static. The rules change if that is not true. Click on the earlier mentioned link to learn more.

    So, for my purposes, that means that my main method would have to look like this.

    public static void main(final String[] args)
    {
       new StaticParentType.StaticChildType();
    }
    

    Here is the full class.

    public class MainClass
    {
    
       public static interface StaticParentType{
          public static class StaticChildType implements StaticParentType {}
       }
    
       public static void main(final String[] args)
       {
          new StaticParentType.StaticChildType();
       }
    
    }
    

    And as a bonus, I went further and set the access modifiers to be what they should have been. I had originally wanted both the nested class and the one that housed it to be private, but changed that once I get my compilation error. Here is the final solution I landed on.

    public class MainClass
    {
    
       private interface StaticParentType{
          static class StaticChildType implements StaticParentType {}
          //apparently, this nested static class cannot be private
          //else it gets a compilation error
       }
    
    
       public static void main(final String[] args)
       {
          new StaticParentType.StaticChildType();
       }
    
    }
    

    A good example of this would java.util.Map.Entry. Entry is a static interface inside of Map, thus, falling under the same rules as this. So, if I want to refer to Entry, I have to do Map.Entry.

    EDIT -- If the syntax above (ParentType.StaticChildType) is a bit ugly, what you can do is do a Static Import.

    Of course, this only works if the class you are statically importing is not in the same file that you are trying to use it in. After all, why would you need to import something that is already in your file?

    To show off what a static import would like in code, here is an example.

    import static java.util.Map.Entry;
    
    public class Abc
    {
    
       public static void main(String[] args)
       {
       
          Entry<String, Integer> e = null;
          //Map.Entry<String, Integer> e = null;
       
       }
    
    }