无法在静态上下文中调用内部类的构造函数 -- “非静态变量,这不能从静态上下文引用” [重复]

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

提问人:davidalayachew 提问时间:7/9/2023 更新时间:7/9/2023 访问量:85

问:

我有一个和一个.喜欢这个。OuterClassNestedClass

public class OuterClass
{

        public class NestedClass
        {



        }

}

每当我尝试在静态上下文中调用构造函数(如静态字段或静态方法)时,我都会收到编译器错误。NestedClass

下面是一个示例代码。

public class OuterClass
{

        public class NestedClass
        {

                public static final NestedClass someStaticField = new NestedClass();

                public static NestedClass someStaticMethod()
                {

                        return new NestedClass();

                }

        }

}

这是我得到的编译器错误。

$ 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

这些错误意味着什么,我应该编写什么才能实现能够在静态上下文中调用构造函数的预期结果?

java 编译器错误 this non-static

评论


答:

-3赞 davidalayachew 7/9/2023 #1

长话短说,问题是因为在 Java 中,如果 my 前面没有修饰符,那么它就被认为是一个内部类,并且内部类不允许有静态字段或方法因此,如果我希望我有静态字段或方法,那么我必须使我的类成为静态嵌套类。意思是,我需要在我的 .NestedClassstaticNestedClassNestedClassstaticclassNestedClass

这是变化。

BEFORE -- public class NestedClass
AFTER  -- public static class NestedClass

对于长版本,这里有一个很棒的教程,由Oracle自己提供,引导您了解这个概念。

https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

简而言之,如果 class 内部有一个类,则 class 被视为嵌套类BAB

嵌套类有两种类型:内部类和静态嵌套类

内部类是指类按照我上面的方式定义——一个类在另一个类中。在直接的例子中,类前面不会有静态修饰符。B

静态嵌套类与内部类完全相同,但它们前面确实有一个静态修饰符。

举个例子。

public class OuterClass
{

        //    not static!
        public class InnerClass
        {

                public static final InnerClass someStaticField = new InnerClass();

                public static InnerClass someStaticMethod()
                {

                        return new InnerClass();

                }

        }
        
        //     static! -- If you don't put the static keyword, then it's not a static class!
        public static class StaticNestedClass
        {

                public static final StaticNestedClass someStaticField = new StaticNestedClass();

                public static StaticNestedClass someStaticMethod()
                {

                        return new StaticNestedClass();

                }


        }

}

如果我尝试编译这个,我会得到相同的 2 个编译错误(就像我的问题一样),但我没有收到编译错误!InnerClassStaticNestedClass

这样做的原因是允许静态嵌套类具有静态字段/方法,但不允许内部类具有静态字段/方法

这是一个严格的规则。这意味着,我唯一可能让我拥有静态字段或方法的方法就是将该内部类转换为静态嵌套类,这是通过将关键字放在关键字前面来完成的。NestedClassstaticclass

这是固定版本。

public class OuterClass
{

        //now its static!
        public static class NestedClass
        {

                public static final NestedClass someStaticField = new NestedClass();

                public static NestedClass someStaticMethod()
                {

                        return new NestedClass();

                }

        }

}

不再有编译错误!

评论

1赞 Alex R 7/9/2023
“内部类不允许有静态字段或方法。”这是完全错误的......你试过吗?此外,要创建实例,您可以编写 .public static Inner instance = new Outer().new Inner()
1赞 user16320675 7/9/2023
这个答案是错误的 - 参见 Java 语言规范 8.1.3。内部类和封闭实例:“特别是,内部类可以声明和继承静态成员 (§8.2),并声明静态初始值设定项 (§8.7),即使内部类本身不是静态的。(Java 16 - JEP 395 中放了限制)
0赞 davidalayachew 7/9/2023
嘿伙计们,感谢您的更正。为了回答你的问题@AlexR我确实尝试过,我循环了几种不同的排列。但我没有尝试那个。无论哪种方式,我的主要错误是没有针对 JLS 验证我的逻辑。再次感谢您的帮助!
0赞 davidalayachew 7/9/2023
感谢您的通知@user16320675我想最近出现了更多实现这一目标的方法
3赞 4 revsuser16320675 #2

问题在于 is 不是 - 既不隐式也不显式地声明为 - 所以它是一个内部类。摘自 Java 语言规范 8.1.3。内部类和封闭实例NestedClassstatic

内部类是不是显式或隐式的嵌套类。static

要创建此类内部类的实例,需要封闭类(外部类)的实例。如果不是在静态上下文中,则在创建此类实例时隐式使用。在静态上下文中,没有,我们必须提供封闭类的实例。这是通过使用限定的类实例创建表达式来实现的,例如:thisthis

outer.new InnerClass()

JLS 15.9 中所述。类实例创建表达式

限定类实例创建表达式允许创建内部成员类及其匿名子类的实例。

可以在 JLS 15.9.2 中找到更多详细信息。确定封闭实例


将其应用于问题的代码,我们可以做到:

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

第二种可能性是,通过声明嵌套类并避免对封闭实例的需求,不使嵌套类成为内部类:static

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

使用哪种解决方案应该基于特定的用例和数据模型,而不仅仅是因为编译器接受它!


注意:从 Java 16 (JEP 359) 开始,内部类的成员是允许的,因此我们可以在内部类中声明记录类。staticstatic

评论

0赞 davidalayachew 7/9/2023
谢谢你的回答!我现在明白了,总有办法做到这一点,但我现在看到他们允许更多。