Java:final关键字的内存使用情况?

17

在类中声明一个final变量(常量),例如:

private static final int MyVar = 255;

如果有100,000个实例声明了这个类,那么这将需要多少内存?

它会将变量链接到类,因此具有1 * MyVar的存储器使用量(忽略内部指针),还是将链接到此变量的实例并创建100,000 * MyVar个副本的存储器使用量?

反应非常迅速!共识似乎是,如果一个变量既是静态的又是final的,则需要1 * MyVar的内存。谢谢大家!


4
重要的是它是静态的事实,就内存分配而言。final 对此没有影响。 - DaveH
12个回答

21
final 关键字与使用的内存量无关,它只表示变量的值不可更改。然而,由于变量被声明为 static,因此只有一个属于类而不是特定实例的变量。这段内容摘自这里

如果一个字段被声明为static,那么无论最终创建多少个该类的实例(可能为零),该字段都只存在一个实例。有时称为类变量的静态字段在类初始化时创建。未声明为静态的字段(有时称为非静态字段)称为实例变量。每当创建类的新实例时,都会为该类或其任何超类中声明的每个实例变量创建一个与该实例关联的新变量。


如果我有一个类,它包含使用 static final 修饰的常量变量,并且只使用这些变量而不创建该类的实例。当应用程序启动时,即使我没有使用这些常量变量,它们是否仍将保留在内存中(或者在栈中,因为这些变量是原始类型)? - Jemshit Iskenderov

12

因为被声明为static,所以只会使用1个*MyVar内存。


2
关于这个问题,还有一个额外的说明:这是每个JVM的情况,所以如果你的程序有多个进程,可能不适用。 - Travis Webb
3
根据Thomas(如下)在JEE环境中,使用隔离的类加载器可以加载多次同一类。此外,在OSGi中,可以加载多个版本的相同类,或者在Virgo等应用程序分区中使用。请注意,“per JVM”应当改为“per classloader”。 - earcam

4
静态声明意味着该类及其子类只有一个实例(除非它们重写MyVar)。
int是32位带符号的2进制补码整数原始数据类型,因此需要4个字节来存储它。如果您的示例未使用static,则只需将其乘以实例数(例如,对于100,000个实例,仅该字段占用0.38兆字节 - 实际类的额外开销)。
在字段上使用final修饰符意味着它不能被指向另一个值(而在类或方法上使用final表示它不能被覆盖)。

如果它是静态的,即每个类只有一次,为什么要乘以实例的数量? - user85421
同意,之前的表述不够清晰,甚至有误导性;已经编辑并加入了“...如果你的例子没有使用静态变量,你只需要将其乘以...” - earcam

3

这是静态的,因此是类作用域 -> 1。

编辑:实际上,这取决于类加载器。通常情况下,您只有一个类的副本,但如果您有多个类加载器/类存储库(可能在应用程序服务器等中),则可能会出现更多。


2
除了静态字段属于它们的类这一事实外,因此每个类(和每个类加载器)只有一个静态变量实例,还有一点很重要,那就是通过编译时常量表达式初始化的静态final变量被内联到使用它们的类中JLS §13.1 The Form of a Binary
引用常量变量(§4.12.4)的字段在编译时解析为所表示的常量值。在二进制文件中不应存在对这样一个常量字段的引用(除了包含该常量字段的类或接口,该类或接口将具有初始化它的代码),并且这样的常量字段必须始终看作已被初始化;永远不应观察到此类字段类型的默认初始值。
因此,在实践中,属于其类的静态final变量的实例不是该变量值的唯一实例-在使用相关变量的类的常量池(或代码)中也有该值的其他实例被内联。
class Foo {
    public static final String S = "Hello, world!";
}

class Bar {
    public static void main(String[] args) {
        // No real access to class Foo here
        // String "Hello, world!" is inlined into the constant pool of class Bar
        String s = Foo.S; 

        System.out.println(s);
    }
}

实际上,这意味着如果您在类Foo中更改Foo.S的值,但不重新编译类Bar,那么类Bar将打印Foo.S的旧值。

1
关键字 "final" 可以帮助您声明一个具有特定内存量的常量,而关键字 "static" 作为其前缀将会给出这个常量的单个实例,无论内存消耗多少...!!!

1

静态意味着每个类只有一个实例,静态变量只创建一次并且可以在不同的对象之间共享。

最终变量一旦初始化就不能改变其值。最终静态变量用于创建常量(不可变)并直接引用,无需使用对象。


1

static 意味着你只会有一个实例。

final 只是意味着你不能重新分配那个值。


1
澄清一下:final 对内存需求没有影响。而 static 则有影响。 - Joachim Sauer

1
关键在于你将变量声明为static,因为静态变量在类的所有实例之间是共享的,因此只需要与变量的一个实例一样多的空间。将变量声明为final使其在声明或构造函数之外不可变。

1

final 使得内存使用量为 1*instances

然而,static 则仅为 1


+1 - 尽管 1 的大小取决于实际使用的 JVM,可能是 4 字节或 8 字节。(在 64 位 JVM 上,由于字对齐问题,您可能会浪费 4 字节。) - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接