我已经在Stack Overflow和Web上的其他地方看到了一些关于静态变量的事情。但是答案对我来说并不清楚。当我认为我找到答案时,其他一些来源与该陈述相矛盾(或者至少,我认为它确实如此)。
例如:m0bius在How does the static keyword work in Java?中告诉我们(在“何时创建这个副本[编辑静态变量]?”)中,静态变量是在运行时创建的。但是,如果我检查https://en.wikipedia.org/wiki/Class_variable(“静态成员变量和静态成员函数”部分),它告诉我在某些语言中会发生相反的情况,并且在其他语言中也会发生相反的情况。
我的问题可以分为两个不同的问题:
我的意思是编译时间与运行时间:
某些代码仅用于此问题的目的:
// MyClass.java
public class MyClass {
public static int instances;
public final static double PI = 3.14159265359
public MyClass() {
instances++;
}
// ...
}
// Main.java ; version 1
public class Main {
public static void main(String args[]) {
System.out.println("I am doing nothing with MyClass");
}
}
// OUTPUT: I am doing nothing with MyClass
// Main.java ; version 2
public class Main {
public static void main(String args[]) {
System.out.println("PI = " + MyClass.PI);
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
System.out.println("instances = " + MyClass.instances);
}
}
OUTPUT:
3.14159265359
2
如果在运行时创建静态和最终静态变量,则在Main的第一个版本中,都不会创建MyClass类的静态变量(实例和PI)。但我希望最终的静态变量PI将在编译时创建(因此它将“嵌入”.class文件中),因为我认为这会有更好的性能(无论类如何发生) MyClass,PI将始终为3.14159265359,因此它也可以放在二进制文件中)。 这可能与静态变量相同,但它可能会在整个程序中发生变化。
在Java中,是在运行时或编译时创建的类的静态变量吗?
如果创建的意思是分配和初始化,那么在编译时不会在Java中“创建”变量。它们都是在运行时创建的。他们是否是static
或static final
与他们分配时无关。
但我希望最终的静态变量PI将在编译时创建(因此它将“嵌入”.class文件中)因为我认为这会有更好的性能......
这不是它在Java中的工作方式。当类文件被“编译”时,它们实际上大部分都被编码。肯定有一些工作已经完成,但我们对编译的看法(就像C这样的语言而言)的超大比例正在运行时发生。当我们研究优化和内联时尤其如此。
编译器确实做了一些前期工作,例如能够提前预先计算字段的值(静态或实例)。例如,如果您像下面这样定义字段,那么乘法将在编译时完成:
private long timeoutMillis = 10 * 24 * 3600 * 1000;
String
s也是如此,如果可能,编译器会将常量字符串附加在一起。以下内容在运行时不使用StringBuilder
,而是在编译时创建单个String
:
private static final String DEFAULT_HEADER = "A long headers that is " +
"broker into two lines\n";
但是,在这两种情况下,字段的分配和初始化(long timeoutMillis
和String DEFAULT_HEADER
)都是在运行时完成的。
如果在运行时创建静态和最终静态变量,则在Main的第一个版本中,都不会创建MyClass类的静态变量(实例和PI)。
在您的示例中,static
字段(final
或不是)在第一次加载类时进行分配和初始化。因此,在你的第一个Main
中,instances
或PI
static
字段永远不会像你提到的那样被创建。在你的第二个例子中。引用MyClass
后,将加载类文件并创建static
字段。