Java 这两种方法有哪些内存(或性能)问题?

Java 这两种方法有哪些内存(或性能)问题?,java,string,string-pool,Java,String,String Pool,作为Java开发人员的新手,已经阅读了String类,但仍然对它的功能感到困惑。因此,我决定编写一个方法,将表单中的用户名大写,john使用以下代码更改为john: 第一种方法 第二种方法(方法链) 对性能或内存膨胀没有实际影响 在第一种方法中,您声明两个指向用户名字符串内容的变量,然后对字符串进行一些更改,创建两个新字符串,然后返回这两个新字符串的串联,这将产生第三个新字符串 第二种方法是使用不可见变量执行相同的操作(在子字符串之后,总是在堆中创建一个新字符串)。concat手术也是一样。因此

作为
Java
开发人员的新手,已经阅读了
String
类,但仍然对它的功能感到困惑。因此,我决定编写一个方法,将表单中的用户名大写,john使用以下代码更改为john:

第一种方法

第二种方法(方法链)


对性能或内存膨胀没有实际影响

在第一种方法中,您声明两个指向用户名字符串内容的变量,然后对字符串进行一些更改,创建两个新字符串,然后返回这两个新字符串的串联,这将产生第三个新字符串


第二种方法是使用不可见变量执行相同的操作(在子字符串之后,总是在堆中创建一个新字符串)。concat手术也是一样。因此,就虚拟机和生成的代码而言,它们将指向相同的对象并生成几乎相同的代码(在内存中创建新空间的字符串)。

它们大多是等效的方法。但是,如果你真的想让这个性能,只有第一个字母需要大写,那么

username.setCharAt(0, (Character.toUpperCase(username.charAt(0)));
您可以将其应用于字符串的其余部分,以便将其他字符设置为小写,如

for (int i = 1; i < username.length(); i++)
    username.setCharAt(i, (Character.toLowerCase(username.charAt(i)));
for(int i=1;i
将此方法与其他方法进行压力测试可能是有意义的(通过数千次调用它来查看它的性能)

编辑

字符串池以稍微慢一点的方式(处理池)创建字符串为代价,节省了大量空间

字符串池有助于为Java运行时节省大量空间 创建字符串需要更多的时间

当我们使用双引号创建字符串时,它首先查找 字符串池中具有相同值的字符串(如果刚刚找到它) 返回引用,否则将在池中创建新字符串并 然后返回引用

然而,使用new操作符,我们强制String类创建一个新的 堆空间中的字符串对象。我们可以使用intern()方法将其放入 池或引用字符串池中的另一个字符串对象 相同的值

资料来源:

因此,如果要将字符串池与不使用它的字符串池进行比较,则需要创建和重新创建相同的字符串文字,并使用新运算符进行比较。在压力测试中,可以比较它们的相对性能。如果要进行比较,我将首先执行此测试:

for (int i = 0; i < 100000; i++) {
    String foo = "abc";
}
for(int i=0;i<100000;i++){
字符串foo=“abc”;
}
vs

for(int i=0;i<100000;i++){
字符串foo=新字符串(“abc”);
}

实际上,您应该更喜欢使用StringBuffer或StringBuilder来实现这些功能

然而,字符串池与这两种方法无关

关于字符串池的典型问题如下所示:

String someString = new String("Shark");

How many strings will be created by the following code snippet? How many strings will exist in the string pool?
答案是-只会创建一个字符串,但会存在两个字符串。
“Shark”
String literal将在编译时放置在字符串池中,构造函数调用将在运行时创建一个新的字符串对象,该对象不在字符串池中,而是在堆中;当满足正常条件时,该对象有资格进行垃圾收集

如果我们在它上面调用了
.intern()
-
新字符串(“Shark”).intern()
,那么答案是“只会创建一个字符串,并且只会存在一个字符串。
.intern()
将从字符串池返回对“Shark”的引用,在编译时放置在那里,并返回由
新字符串创建的字符串(“Shark”)
将被垃圾收集,因为不再有任何东西引用它

字符串池问题的另一个示例是:

        String s1 = "Shark";
        String s2 = "Shark";
        String s3 = new String("Shark");
        String s4 = new String("Shark").intern();

        System.out.println("s1 == s2 :"+(s1==s2));
        System.out.println("s1 == s3 :"+(s1==s3));
        System.out.println("s1 == s4 :"+(s1==s4));

What will be printed out by this code snippet?
当然,它会打印出以下内容:

s1 == s2 :true
s1 == s3 :false
s1 == s4 :true
为完整起见,上述示例将在字符串池中创建一个字符串,在堆中创建一个。一个用于两个相同的
“Shark”
文本-在编译期间,一个用于堆中的
新字符串(“Shark”)
实例化,以及
新字符串(“Shark”).intern()
将返回对编译时创建的
“Shark”
文本的引用


每一个字符串文字都将在字符串池中结束。但是您的问题,如前所述,实际上与典型的字符串池问题没有任何关系。

这两个代码片段之间没有真正的区别。它们都与字符串池没有任何关系。第一种方法最多创建5个字符串,第二种方法比第一种方法多创建一个,最多6个。我可能误解了这个问题更多的是关于“字符串池”,而不是优化这个微不足道的示例。如果是这样的话,请告诉我,这样我就可以删除答案,而不是被否决而忘记:数据值是
形式的字符串。。。
。您的代码中没有文本。对他的示例的回答很好,但它完全跳过了“字符串池”的要点我可能误解了这一点,认为这是问题的重点。@Shark感谢建设性的批评,我正在编辑我的答案来解决这个问题。没问题,不客气,但我可能错了,我误解了这实际上是关于“字符串池”而不是“如何优化此代码段”:您可能已经做对了。您可能还想演示如何使用StringBuilder/StringBuffer来实现这一点,以获得最佳性能或最佳性能+线程安全。如果您没有这样做,那么为什么要使用
setCharAt
方法呢?您不能使用字符串来实现这一点-它是不可变的。您的第一个代码片段(
String someString=新字符串(“Shark”)
String someString = new String("Shark");

How many strings will be created by the following code snippet? How many strings will exist in the string pool?
        String s1 = "Shark";
        String s2 = "Shark";
        String s3 = new String("Shark");
        String s4 = new String("Shark").intern();

        System.out.println("s1 == s2 :"+(s1==s2));
        System.out.println("s1 == s3 :"+(s1==s3));
        System.out.println("s1 == s4 :"+(s1==s4));

What will be printed out by this code snippet?
s1 == s2 :true
s1 == s3 :false
s1 == s4 :true