如何在Java中处理静态final和static成员?

问题描述 投票:1回答:1

我已经在Stack Overflow和Web上的其他地方看到了一些关于静态变量的事情。但是答案对我来说并不清楚。当我认为我找到答案时,其他一些来源与该陈述相矛盾(或者至少,我认为它确实如此)。

例如:m0bius在How does the static keyword work in Java?中告诉我们(在“何时创建这个副本[编辑静态变量]?”)中,静态变量是在运行时创建的。但是,如果我检查https://en.wikipedia.org/wiki/Class_variable(“静态成员变量和静态成员函数”部分),它告诉我在某些语言中会发生相反的情况,并且在其他语言中也会发生相反的情况。

我的问题可以分为两个不同的问题:

  • 在Java中,是在运行时或编译时创建的类的静态变量吗?
  • 在Java中,是在运行时或编译时创建的类的最终静态变量?

我的意思是编译时间与运行时间:

  • 编译时:编译源代码时(所以当创建.class文件时)
  • 运行时间:程序实际运行时

某些代码仅用于此问题的目的:

// 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 static final
1个回答
4
投票

在Java中,是在运行时或编译时创建的类的静态变量吗?

如果创建的意思是分配和初始化,那么在编译时不会在Java中“创建”变量。它们都是在运行时创建的。他们是否是staticstatic final与他们分配时无关。

但我希望最终的静态变量PI将在编译时创建(因此它将“嵌入”.class文件中)因为我认为这会有更好的性能......

这不是它在Java中的工作方式。当类文件被“编译”时,它们实际上大部分都被编码。肯定有一些工作已经完成,但我们对编译的看法(就像C这样的语言而言)的超大比例正在运行时发生。当我们研究优化和内联时尤其如此。

编译器确实做了一些前期工作,例如能够提前预先计算字段的值(静态或实例)。例如,如果您像下面这样定义字段,那么乘法将在编译时完成:

private long timeoutMillis = 10 * 24 * 3600 * 1000;

Strings也是如此,如果可能,编译器会将常量字符串附加在一起。以下内容在运行时不使用StringBuilder,而是在编译时创建单个String

private static final String DEFAULT_HEADER = "A long headers that is " +
   "broker into two lines\n";

但是,在这两种情况下,字段的分配和初始化(long timeoutMillisString DEFAULT_HEADER)都是在运行时完成的。

如果在运行时创建静态和最终静态变量,则在Main的第一个版本中,都不会创建MyClass类的静态变量(实例和PI)。

在您的示例中,static字段(final或不是)在第一次加载类时进行分配和初始化。因此,在你的第一个Main中,instancesPI static字段永远不会像你提到的那样被创建。在你的第二个例子中。引用MyClass后,将加载类文件并创建static字段。

© www.soinside.com 2019 - 2024. All rights reserved.