静态嵌套 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。
我在 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。