将创build多less个String对象
我有以下Java代码:
public String makinStrings() { String s = "Fred"; s = s + "47"; s = s.substring(2, 5); s = s.toUpperCase(); return s.toString(); }
这个问题很简单:调用这个方法时会创build多less个String
对象?
在开始的时候,我回答说创build了5个String对象,但是我的书的答案是只有3个对象被创build,没有给出解释(这是一个SCJP问题)。
从我的angular度来看,有5个对象:“弗雷德”,“47”,“弗雷德47”,“ED4”,“ED4”。
我也在一个SCJP模拟考试中发现了这个问题,同样的答案3。
“Fred”和“47”将来自string文字池。 因此,当方法被调用时,它们不会被创build。 相反,当类被加载时(或者更早,如果其他类使用具有相同值的常量),它们将被放置在那里。
“Fred47”,“ed4”和“ED4”是将在每个方法调用中创build的3个String
对象。
程序的代码中往往含有大量的string文字。 在Java中,这些常量被收集在一个叫做string表的地方以提高效率。 例如,如果在十个不同的地方使用string"Name: "
,则JVM(通常)只有该String的一个实例,在所有使用它的十个地方,引用都指向一个实例。 这节省了内存。
这个优化是可能的,因为String
是不可变的 。 如果有可能改变一个string,改变它一个地方将意味着其他九个改变。 这就是为什么任何改变string的操作都会返回一个新的实例。 这就是为什么如果你这样做:
String s = "boink"; s.toUpperCase(); System.out.println(s);
它打印boink
,而不是BOINK
。
现在还有一个棘手的问题: java.lang.String
多个实例可能指向相同的底层char[]
作为它们的字符数据,换句话说,它们可能是同一个char[]
上的不同视图 ,只需使用一个slice的数组。 再次,对效率进行优化。 substring()
方法是发生这种情况的一种情况。
s1 = "Fred47"; //String s1: data=[ 'F', 'r', 'e', 'd', '4', '7'], offset=0, length=6 // ^........................^ s2 = s1.substring(2, 5); //String s2: data=[ 'F', 'r', 'e', 'd', '4', '7'], offset=2, length=3 // ^.........^ // the two strings are sharing the same char[]!
在你的SCJP问题中,所有这些归结为:
- string
"Fred"
取自String表。 - string
"47"
取自String表。 - string
"Fred47"
在方法调用期间创build。 // 1 - 在方法调用期间创buildstring
"ed4"
, 与"Fred47"
// 2 共享相同的后备数组 - string
"ED4"
在方法调用期间创build。 // 3 -
s.toString()
不创build一个新的,它只是返回this
。
一个有趣的边缘情况:考虑如果你有一个非常长的string,例如,从互联网上获取的网页,假设char[]
的长度是两兆字节会发生什么情况。 如果你把这个substring(0, 4)
,你得到一个新的string, 看起来只有四个字符长,但它仍然共享这两兆字节的后备数据。 这在现实世界中并不常见,但这可能是一个巨大的内存浪费! 在这种罕见的情况下,如果遇到这个问题,可以使用new String(hugeString.substring(0, 4))
来创build一个带有新的小的后备数组的String。
最后,可以在运行时通过调用intern()
将string强制到string表中。 在这种情况下的基本规则:不要这样做。 扩展规则:除非您使用内存分析器来确定这是一个有用的优化,否则不要这样做。
基于javap输出,看起来像concatenation期间创build了一个StringBuilder,而不是一个String。 然后有三个string调用substring(),toUpperCase()和toString()。
最后一次调用不是多余的,因为它将StringBuilder转换为String。
>javap -c Test Compiled from "Test.java" public java.lang.String makinStrings(); Code: 0: ldc #5; //String Fred 2: astore_1 3: new #6; //class java/lang/StringBuilder 6: dup 7: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V 10: aload_1 11: invokevirtual #8; //Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #9; //String 47 16: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #10; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: aload_1 24: iconst_2 25: iconst_5 26: invokevirtual #11; //Method java/lang/String.substring:(II)Ljava/lang/String; 29: astore_1 30: aload_1 31: invokevirtual #12; //Method java/lang/String.toUpperCase:()Ljava/lang/String; 34: astore_1 35: aload_1 36: invokevirtual #13; //Method java/lang/String.toString:()Ljava/lang/String; 39: areturn
}
- 在字节中设置特定位
- 在mongoDB w / Java驱动程序中获取最后插入的文档的ID
- 将Java Appletembedded到.html文件中
- 将@RequestBody中的多个variables传递给使用Ajax的Spring MVC控制器
- 如何获得当前的一周和一个月的第一天?
- java.lang.UnsatisfiedLinkError:java.library.path中没有rxtxSerial
- Spring CrudRepository findByInventoryIds(List <Long> inventoryIdList) – 相当于IN子句
- 如何使用JPA和Hibernate解决LazyInitializationException
- 检查一个类是否是java.lang.Enum