静态嵌套 class 的实例变量与外部 class 的静态变量

Instance variable of a static nested class vs static variable of an outer class

我在 java 中使用静态嵌套 class 用于特定用例。下面显示了一个最小的例子:

public class Foo {
    static int fooInner = getInner(); // CASE 1 

    private static class StaticFoo {
        int fooInner = getInner(); // CASE 2

        public int useFooInner(){
            System.out.println(fooInner);
            //do something
        }
    }
}

问题是case 1和case 2的内存分配有什么不同?或者是一样的? 如果我也将 case 2 变量设为静态怎么办?内存使用情况会有所不同吗?

注意:请不要提及会发生阴影。虽然我已经把两个变量都放在那里,但它是一个“或”案例,这就是为什么“案例”。

PS:感觉内存占用应该是一样的。由于嵌套的 class 是静态的,它不会为每个对象创建,因此实例变量 fooInner (案例 2)也只会创建一次。因此,getInner() 函数只会 运行 一次。但它只是在抽象层面+直觉。一个更具描述性的答案将不胜感激!

它们是不同的。

从内存分配的角度来看,静态内部 class 与顶级 class 没有什么不同。您的 StaticFoo 将被编译为 class (Foo$StaticFoo.class),它在运行时基本上独立于其父 class。在编译时,有对私有成员的访问检查。

因此,在情况 1 中,您在 class 中有一个静态字段。它将被分配为堆上 Foo.class 对象上的一个字段。每个 ClassLoader 将只有一个实例加载 Foo class,这通常意味着整个 JVM 只有一个共享实例。

在情况 2 中,您在 Foo$StaticFoo class 中有一个 实例 字段。在堆上,将为每个创建的 StaticFoo 实例分配 space(并分配一个值)。创建的每个 StaticFoo 都将访问它自己的该字段实例,并且由于它不是 final,每个实例的值都可以独立更改。

如果你把StaticFoo.fooInner改成static,那就和情况1完全一样了

注意: 以上仅适用于 Java 8 及更高版本。对于早期的 JVM,在每种情况下分配的 amount 内存仍然符合上面的描述,但是静态变量,以及每个 ClassLoader 的单例,也存储在不同的内存池中:PermGen Space 而不是主堆。有关详细信息,请参阅 this answer