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

Java性能:私有静态最终字符串与本地字符串?在堆空间中创建的对象数,java,string,performance,object,jvm,Java,String,Performance,Object,Jvm,在这部法典中, 每次调用goodMethod时,它都将使用在堆空间中创建的唯一对象和静态字 我的问题是:当我调用badMethod时,它是否会在每次调用该方法时在堆空间中创建一个新的String对象?所以,如果我每次调用我的方法1_200_000,它会在堆空间中创建1_200_000 string对象吗 毫无疑问,第一种方法对于代码的可读性和可维护性更好。我只是想问一下在内存中创建的对象的数量 谢谢 我在谷歌上读了很多关于这一点的文章,但没有找到有争议或证据的回应。请也如果你知道我可以如何测试这

在这部法典中, 每次调用goodMethod时,它都将使用在堆空间中创建的唯一对象和静态字

我的问题是:当我调用badMethod时,它是否会在每次调用该方法时在堆空间中创建一个新的String对象?所以,如果我每次调用我的方法1_200_000,它会在堆空间中创建1_200_000 string对象吗

毫无疑问,第一种方法对于代码的可读性和可维护性更好。我只是想问一下在内存中创建的对象的数量

谢谢

我在谷歌上读了很多关于这一点的文章,但没有找到有争议或证据的回应。请也如果你知道我可以如何测试这个,谢谢分享

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());
编辑:我不是在问连接,我已经从示例代码中删除了连接

连接编译时常量字符串将导致编译时常量字符串。因此,这无关紧要——连接不会在运行时发生

如果字符串不是编译时常量,那么您将始终需要一个新的对象,而不是在普通情况下。

连接编译时常量字符串将产生编译时常量字符串。因此,这无关紧要——连接不会在运行时发生


如果字符串不是编译时常量,那么您总是需要一个新的对象,而不是在普通情况下。

事实上,我认为jvm并不是那么愚蠢。在这个阶段,它可以检查您是否已经将hello作为字符串,并且不再创建它。只是重复使用它。问题是当您使用构造函数newstringhello创建唯一字符串或字符串时。然后每次一个新的空间被占用


另外,您还可以通过连接+来创建一个唯一的字符串。现在在您的示例System.out.printlnhhello+world中;如果还不存在hello、world和helloworld字符串,将尝试创建它们。

事实上,我认为jvm并不是那么愚蠢。在这个阶段,它可以检查您是否已经将hello作为字符串,并且不再创建它。只是重复使用它。问题是当您使用构造函数newstringhello创建唯一字符串或字符串时。然后每次一个新的空间被占用


另外,您还可以通过连接+来创建一个唯一的字符串。现在在您的示例System.out.printlnhhello+world中;如果不存在hello、world和helloworld字符串,将尝试创建。

Java具有存储字符串的字符串池。如果使用已经存在的字符串,则不会创建新字符串。 当你改变字符串时会发生什么?为什么它不改变该字符串的所有用途?原因字符串是不可变的-这意味着一旦在内存中创建它就永远不会被更改-只能被删除

处理字符串时,例如:

String TEST = "test";
test += "copy paste";
字符串测试并没有在内存中更改,只是在字符串池中创建了新字符串,或者新字符串已经存在,并且从现在开始的变量测试将指向new或from heap string。在GC完成其工作之前,旧的一次测试仍然存在

试试这篇文章-
Java有一个存储字符串的字符串池,这是一个相当简单的概念。如果使用已经存在的字符串,则不会创建新字符串。 当你改变字符串时会发生什么?为什么它不改变该字符串的所有用途?原因字符串是不可变的-这意味着一旦在内存中创建它就永远不会被更改-只能被删除

处理字符串时,例如:

String TEST = "test";
test += "copy paste";
字符串测试并没有在内存中更改,只是在字符串池中创建了新字符串,或者新字符串已经存在,并且从现在开始的变量测试将指向new或from heap string。在GC完成其工作之前,旧的一次测试仍然存在

试试这篇文章-
这是一个相当简单的概念

这两个示例都是相同的,都适用于内存中的三个对象hello,world,helloworld。两个文本的串联是编译时表达式。您可以简单地测试这一点:

// test one object used for constants
String stringOne = "constant";
String stringTwo = "constant";
assertThat(stringOne)
  .isSameAs(stringTwo);

// test one object is used for string literals concatenation
stringOne = "constant2";
stringTwo = "constant" + "2";
assertThat(stringOne)
  .isSameAs(stringTwo);

这两个示例都是相同的,都适用于内存中的三个对象hello、world、helloworld。两个文本的串联是编译时表达式。您可以简单地测试这一点:

// test one object used for constants
String stringOne = "constant";
String stringTwo = "constant";
assertThat(stringOne)
  .isSameAs(stringTwo);

// test one object is used for string literals concatenation
stringOne = "constant2";
stringTwo = "constant" + "2";
assertThat(stringOne)
  .isSameAs(stringTwo);

goodMethod实现参考字符串池。
badMethod实现引用对象。当我们将字符串直接作为println方法传递时,它被称为对象。

goodMethod实现引用字符串池。 badMethod实现引用对象。当我们将字符串直接作为println方法传递时,它被称为object

毫无疑问,第一种方法对于代码的可读性和可维护性更好。我只是想问一下在内存中创建的对象的数量

我认为第一个示例的可读性和可维护性较差,但在运行时它是相同的,没有更快或更慢

System.out.println("hello");
你完全知道它将打印什么,而不必环顾全班

在第一种情况下,您不知道它将打印什么unles 这是你的支票

private static final String HELLO = "hello";
private static final String HELLO = "Hello";
private static final String HELLO = "HELLO";
private static final String HELLO = "G'Day";
i、 它的可读性较差,因为您必须查看类中的两个不同位置,以了解代码行的作用

注:

这两种方法都不创建任何对象。 即使他们这样做了,这也会影响到生产成本 每次打印时,都会锁定System.out,但与 写入屏幕的成本是创建对象的数千倍。 另一个例子

这两个示例都不会创建任何字符串,但每个put都会创建一个新的Map.Entry对象

毫无疑问,第一种方法对于代码的可读性和可维护性更好。我只是想问一下在内存中创建的对象的数量

我认为第一个示例的可读性和可维护性较差,但在运行时它是相同的,没有更快或更慢

System.out.println("hello");
你完全知道它将打印什么,而不必环顾全班

在第一种情况下,除非您检查,否则您不知道它将打印什么

private static final String HELLO = "hello";
private static final String HELLO = "Hello";
private static final String HELLO = "HELLO";
private static final String HELLO = "G'Day";
i、 它的可读性较差,因为您必须查看类中的两个不同位置,以了解代码行的作用

注:

这两种方法都不创建任何对象。 即使他们这样做了,这也会影响到生产成本 每次打印时,都会锁定System.out,但与 写入屏幕的成本是创建对象的数千倍。 另一个例子

两个示例都不会创建任何字符串,但每个put都会创建一个新的Map.Entry对象。

对于代码示例

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");
    }
}
好方法和坏方法之间根本没有区别

关键的一点是,不仅hello和world是编译时常量,而且hello和world也是编译时常量

正如它所说:

常量变量是使用常量表达式初始化的基元类型或字符串类型的最终变量。变量是否为常量变量可能涉及类初始化、二进制兼容性、可达性和确定赋值

以及:

对常量变量字段的引用必须在编译时解析为常量变量的初始值设定项表示的值V

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

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

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

您不需要详细了解字节码,就可以看到goodMethod和badMethod两种方法的编译代码是相同的。当然,相同的代码不能有与创建方式相关的性能差异

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

关于编码风格,我同意。当常量变量的名称没有提供额外的含义时,使用常量变量并不能改善代码。如果没有这样的含义,实际值比变量名更能说明问题。有关代码示例,请参见。

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");
    }
}
好方法和坏方法之间根本没有区别

关键的一点是,不仅hello和world是编译时常量,而且hello和world也是编译时常量

正如它所说:

常量变量是使用常量表达式初始化的基元类型或字符串类型的最终变量。变量是否为常量变量可能涉及类初始化、二进制兼容性、可达性和确定赋值

以及:

对常量变量字段的引用必须在编译时解析为常量变量的初始值设定项表示的值V

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

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

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

您不需要详细了解字节码,就可以看到goodMethod和badMethod两种方法的编译代码是相同的。当然,相同的代码不能有与创建方式相关的性能差异

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

关于编码风格,我同意。使用常量变量不会改善代码的性能
名称不提供其他含义。如果没有这样的含义,实际值比变量名更能说明问题。另请参见。

两者之间没有区别。对于这两种情况,在运行时都不会发生字符串创建或连接。如果怀疑,请尝试使用带有选项的javap进行反汇编,以显示代码。两者之间没有区别。对于这两种情况,在运行时都不会发生字符串创建或连接。如果怀疑,请尝试使用带有选项的javap进行反汇编,以显示代码。