Search code examples
javacompiler-errorsstaticthisnon-static

Can't call constructor of inner class in a static context -- "non-static variable this cannot be referenced from a static context"


I have an OuterClass and an NestedClass. Like this.

public class OuterClass
{

        public class NestedClass
        {



        }

}

Whenever I try to call the constructor of NestedClass in a static context (like as a static field or a static method), I get a compiler error.

Here is an example code.

public class OuterClass
{

        public class NestedClass
        {

                public static final NestedClass someStaticField = new NestedClass();

                public static NestedClass someStaticMethod()
                {

                        return new NestedClass();

                }

        }

}

And here are the compiler errors that I get.

$ javac OuterClass.java
OuterClass.java:7: error: non-static variable this cannot be referenced from a static context
                public static final NestedClass someStaticField = new NestedClass();
                                                                 ^
OuterClass.java:12: error: non-static variable this cannot be referenced from a static context
                        return new NestedClass();
                               ^
2 errors

What do these errors mean, and what should I be writing instead to achieve the desired outcome of being able to call the constructor in a static context?


Solution

  • The problem is that the NestedClass is not static - neither implicitly nor explicitly declared as such - so it is an inner class. From Java Language Specification 8.1.3. Inner Classes and Enclosing Instances:

    An inner class is a nested class that is not explicitly or implicitly static.

    To create an instance of such inner class, an instance of the enclosing (outer class) is needed. If not in a static context, this is implicitly used when creating such an instance. In a static context, there is no this and we must provide the instance of the enclosing class. This is accomplish by using a qualified class instance creation expression like:

    outer.new InnerClass()

    as described in JLS 15.9. Class Instance Creation Expressions:

    A qualified class instance creation expression enables the creation of instances of inner member classes and their anonymous subclasses.

    More details can be found in JLS 15.9.2. Determining Enclosing Instances.


    Applying that to the code of the question, we could do:

    public class OuterClass
    {
    
        public class NestedClass // actually an Inner Class
        {
            public static final NestedClass someStaticField = new OuterClass().new NestedClass();
    
            public static NestedClass someStaticMethod()
            {
                var outer = new OuterClass();
                return outer.new NestedClass();
            }
        }
    }
    

    A second possibility would be to not make the nested class an inner class by declaring it as static and avoiding the need for an enclosing instance:

    public class OuterClass
    {
    
        // static added to following declaration
        public static class NestedClass
        {
            public static final NestedClass someStaticField = new NestedClass();
    
            public static NestedClass someStaticMethod()
            {
                return new NestedClass();
            }
        }
    }
    

    Which solution to use should be based on the specific use case and data model, not just because the compiler accepts it!


    Note: static members of inner classes are allowed since Java 16 (JEP 359), so we can have record classes, which are static, declared in inner classes.