Java 性能:私有静态最终字符串与本地字符串?在堆空间中创建的对象数

mou*_*d m 1 java string performance jvm object

在这段代码中,每次我调用 goodMethod() 时,它都会使用在堆空间中创建的唯一对象和静态字。

我的问题是:当我调用 badMethod() 时,是否会在每次调用此方法时在堆空间中创建一个新的 String 对象?因此,如果我调用我的方法 1_200_000 次,它是否会在堆空间中创建 1_200_000 字符串对象?

毫无疑问,第一种方法更好(为了代码的可读性和可维护性)。我只是在这里询问内存中创建的对象数量

谢谢

我在谷歌上阅读了很多关于此的内容,但没有找到带有论点或证据的回复。如果你知道我如何测试这个,也请谢谢分享。

public class Main {

    private static final String HELLO = "hello";
    private static final String WORLD = "world";

    public static void main(String[] args) {

        for (int i = 0; i < 1_200_000; i++) {
           goodMethod();
           badMethod();
        }

    }

    private static void goodMethod(){
        System.out.println(HELLO);
        System.out.println(WORLD);
    }

    private static void badMethod(){
        System.out.println("hello");
        System.out.println("world");
    }

}


// an other example 
Map<String, Object> map = new HashMap<>();
map.put("myKey", xxx.getYYY());
// somewhere else 
map.put("myKey", zzz.getYYY());

// instead of : 
private static final String MY_KEY = "myKey"
map.put(MY_KEY, xxx.getYYY());
map.put(MY_KEY, zzz.getYYY());
Run Code Online (Sandbox Code Playgroud)

编辑:我不是在问连接,我已经从示例代码中删除了连接

Hol*_*ger 5

对于代码示例

public class Main {
    private static final String HELLO = "hello";
    private static final String WORLD = "world";

    private static void goodMethod(){
        System.out.println(HELLO);
        System.out.println(WORLD);
    }

    private static void badMethod(){
        System.out.println("hello");
        System.out.println("world");
    }
}
Run Code Online (Sandbox Code Playgroud)

goodMethod()和根本没有区别badMethod()

关键的一点是,不仅"hello""world"是编译时间常数,但HELLOWORLD是也。

正如Java® 语言规范所说:

常量变量final原始类型或类型的变量String,其与一个常量表达式(初始化§15.28)。变量是否为常量变量可能会影响类初始化(第12.4.1 节)、二进制兼容性(第13.1 节)、可达性(第14.21 节)和明确赋值(第16.1.1 节)。

§13.1 中

对作为常量变量(第4.12.4 节)的字段的引用必须在编译时解析为常量变量的初始值设定项所表示的值 V。

如果这样的字段是静态的,则二进制文件的代码中不应存在对该字段的引用,包括声明该字段的类或接口。

换句话说,字段引用HELLOWORLD在编译时得到解析并替换为它们的常量值,就像您首先编写这些值一样。

您可以通过查看字节码来验证这一点,例如javap -p -c Main

Compiled from "Main.java"
public class Main {
  private static final java.lang.String HELLO;

  private static final java.lang.String WORLD;

  public Main();
    Code:
       0: aload_0
       1: invokespecial #1     // Method java/lang/Object."<init>":()V
       4: return

  private static void goodMethod();
    Code:
       0: getstatic     #2     // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #4     // String hello
       5: invokevirtual #5     // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: getstatic     #2     // Field java/lang/System.out:Ljava/io/PrintStream;
      11: ldc           #6     // String world
      13: invokevirtual #5     // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      16: return

  private static void badMethod();
    Code:
       0: getstatic     #2     // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #4     // String hello
       5: invokevirtual #5     // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: getstatic     #2     // Field java/lang/System.out:Ljava/io/PrintStream;
      11: ldc           #6     // String world
      13: invokevirtual #5     // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      16: return
}
Run Code Online (Sandbox Code Playgroud)

您无需了解字节码的所有细节即可看到两种方法的编译代码,goodMethod()并且badMethod()是相同的。当然,相同的代码不能因创建方式而产生性能差异。

这同样适用于您的第二个示例,使用字符串文字或常量变量之间没有区别。

关于编码风格,我同意Peter Lawrey 的回答。当其名称没有提供额外的含义时,使用常量变量不会改进代码。如果没有这样的含义,实际值比变量名更能说明问题。另请参阅此答案