为什么我们不能在(非静态)内部类中使用静态方法?

Rah*_*arg 140 java static class inner-classes

为什么我们不能在非静态内部类中使用静态方法?

如果我使内部类静态,它的工作原理.为什么?

Bil*_*ard 108

因为内部类的实例与其外部类的实例隐式关联,所以它本身不能定义任何静态方法.由于静态嵌套类不能直接引用其封闭类中定义的实例变量或方法,因此它只能通过对象引用来使用它们,在静态嵌套类中声明静态方法是安全的.

  • 臭虫这个词......我不认为这个词意味着你认为它意味着什么. (39认同)
  • 一个更合适的短语将是"作为一个mothertrucker'烦人".不明白为什么Java不允许这样做.有时,我希望内部类使用父类的属性,但保留静态方法以获得更好的命名空间.这有什么本质上的错误吗?:( (23认同)
  • 在C++中你可以拥有,所以这是Java语言中的一个错误. (14认同)
  • 我知道一个内部类与它的外部类的一个实例相关联,我知道我们能够在内部类中声明静态成员是有点无用但我仍然在问为什么内部类不能声明静态成员? (6认同)
  • 究竟.我想写一个实用程序内部类.*它的一些*方法将受益于对外部类的访问,所以我不能使它成为静态的,但*它的一些方法只是实用函数.为什么我不能调用`ABsync(X)`或甚至(从A内)`B.sync(x)`? (6认同)
  • 不幸的是,我认为这个"答案"甚至没有试图回答这个问题(大多数问题甚至不是非静态类).另一方面,似乎这个问题唯一真正的答案是"因为Java的作者希望每个人都受苦". (2认同)

Edd*_*die 45

在非静态内部类中允许静态方法没有多大意义; 你怎么去访问它?您无法访问(至少最初)非静态内部类实例而无需通过外部类实例.创建非静态内部类没有纯粹的静态方法.

对于外部类Outer,您可以访问如下静态方法test():

Outer.test();
Run Code Online (Sandbox Code Playgroud)

对于静态内部类Inner,您可以innerTest()像这样访问其静态方法:

Outer.Inner.innerTest();
Run Code Online (Sandbox Code Playgroud)

但是,如果Inner不是静态的,那么现在没有纯粹的静态方法来引用该方法innertest.非静态内部类与其外部类的特定实例相关联.函数与常量不同,Outer.Inner.CONSTANT因为对函数调用Outer.Inner.staticFunction();不保证引用是明确的.假设您有Inner.staticFunction()那些getState()定义的调用Outer.如果您尝试调用该静态函数,则现在对Inner类有一个不明确的引用.也就是说,你在内部类的哪个实例上调用静态函数?这很重要.看,由于对外部对象的隐式引用,没有真正的静态方法来引用该静态方法.

保罗贝洛拉是正确的,语言设计师可以允许这样做.然后,他们必须小心地禁止对非静态内部类的静态方法中对外部类的隐式引用的任何访问.在这一点上,如果你不能引用外部类,除了静态之外,这是一个内部类的值是什么?如果静态访问没问题,为什么不将整个内部类声明为静态呢?如果你只是让内部类本身是静态的,那么你没有对外部类的隐式引用,并且你不再有这种歧义.

如果您确实需要非静态内部类的静态方法,那么您可能需要重新考虑您的设计.

  • "在非静态内部类中允许静态方法并没有多大意义;如何访问它?" 你可以调用`Outer.Inner.staticMethod()`,就像你可以访问`Outer.Inner.CONSTANT`一样."如果不通过外部类实例,则无法访问...非静态内部类实例." 你为什么需要一个实例?你不需要`Outer`的实例来调用`Outer.staticMethod()`.我知道这是挑剔的,但我的观点是,以这种方式构建答案是没有意义的.恕我直言,如果他们愿意,语言设计师可以允许它. (22认同)
  • -1我不得不同意你在这里采取的角度.当然我们可以引用内部类类型,例如`Outer.Inner i = new Outer().new Inner();`此外,内部类*是*允许根据JLS§15.28声明静态*常量*. (5认同)
  • @Eddie你不能在静态方法中引用实例字段,因此没有与无法引用隐式实例字段"Outer.this"相关的冲突.我同意Java语言设计者没有理由在内部类中允许静态方法或非最终静态字段,因为内部类中的所有内容都应该在封闭类的上下文中. (3认同)
  • 是的,内部类可以声明静态*常量*.这与静态方法无关!虽然您*可以*非静态地引用静态方法,但不建议这样做.所有代码质量工具都抱怨这种参考并且有充分的理由.你错过了我的观点.我从未说过没有办法引用静态内部类.我说没有STATIC方法来引用非静态外部类的内部类的静态方法.因此,没有适当的方式来引用它. (2认同)

gus*_*afc 20

我有一个理论,可能是也可能不正确.

首先,您应该了解一些关于如何在Java中实现内部类的事情.假设你有这门课:

class Outer {
    private int foo = 0;
    class Inner implements Runnable {
        public void run(){ foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(); }
}
Run Code Online (Sandbox Code Playgroud)

编译它时,生成的字节码看起来就像你写了这样的东西:

class Outer {
    private int foo = 0;
    static class Inner implements Runnable {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public void run(){ this$0.foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(this); }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我们在非静态内部类中允许静态方法,您可能希望执行类似这样的操作.

class Outer {
    private int foo = 0;
    class Inner {
        public static void incrFoo(){ foo++; }
    }
}
Run Code Online (Sandbox Code Playgroud)

......看起来相当合理,因为这个Inner类似乎每个Outer实例都有一个化身.但正如我们上面所看到的,非静态内部类实际上只是静态"内部"类的语法糖,所以最后一个例子大致相当于:

class Outer {
    private int foo = 0;
    static class Inner {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public static void incrFoo(){ this$0.foo++; }
    }
}
Run Code Online (Sandbox Code Playgroud)

......这显然this$0是行不通的,因为它是非静态的.这种解释了为什么不允许使用静态方法(尽管你可以使参数允许静态方法,只要它们不引用封闭对象),以及为什么你不能有非最终静态字段(如果来自不同对象的非静态内部类的实例共享"静态",那将是违反直觉的.这也解释了为什么最终场允许的(只要他们不引用封闭的对象).

  • 但这只是一个正常的"尝试从静态上下文访问非静态变量"类型错误 - 与顶级静态方法试图访问它自己的类的实例变量没什么不同. (7认同)
  • 我喜欢这个anwser,因为它实际上解释了为什么它在技术上不可能,即使它在语法上似乎是可能的. (2认同)

Don*_* Li 7

唯一的原因是"不是必须",为什么还要费心去支持呢?

从语法上讲,没有理由禁止内部类具有静态成员.虽然一个实例Inner与一个实例关联Outer,但是如果java决定这样做,它仍然可以Outer.Inner.myStatic用来引用一个静态成员Inner.

如果您需要在所有实例之间共享某些内容Inner,您可以将它们Outer作为静态成员放入.这并不比使用静态成员更糟糕Inner,其中Outer仍然可以访问任何私有成员Inner(不会改进封装).

如果您需要Inner在由一个outer对象创建的所有实例之间共享某些内容,那么将它们Outer作为普通成员放入类中会更有意义.

我不同意"静态嵌套类几乎只是顶级类"的观点.我认为将静态嵌套类/内部类视为外部类的一部分更好,因为它们可以访问外部类的私有成员.外族的成员也是"内在阶级的成员".因此,不需要在内部类中支持静态成员.外部类中的普通/静态成员就足够了.