String 的内存分配与拼接操作,mysql 数据库教程课后题答案
在 jdk6 中 StringTable 是固定的,就是 1009 的长度,所以如果常量池中的字符串过多就会导致效率下降很快,StringTablesize 设置没有要求。
在 jdk7 中,StringTable 的长度默认值是 60013,StringTablesize 设置没有要求
在 jdk8 中,设置 StringTa
ble 长度的话,1009 是可以设置的最小值
[](
)String 的内存分配
在 Java 语言中有 8 种基本数据类型和一种比较特殊的类型 String。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。
常量池就类似一个 Java 系统级别提供的缓存。8 种基本数据类型的常量池都是系统协调的,String 类型的常量池比较特殊,存储的主要方法有两种:
直接使用双引号声明出来的 String 对象会直接存储在常量池中。
如果不是用双引号声明的 String 对象,可以使用 String 提供的 intern()方法。
在 JDK 7 以后,内部字符串不再分配在 Java 堆的永久代中(永久代垃圾回收频率低),而是分配在 Java 堆的主要部分(年轻代和老年代),所有的字符串都保存在堆中,与应用程序创建的其他对象放在一起。这种变化将导致更多的数据驻留在主 Java 堆中,而更少的数据在永久代中,因此可能需要调整堆的大小。
在加载许多类或大量使用 String.intern()方法的大型应用程序中可以看到这个改动的明显效果。
样例:
class Memory {
public static void main(String[] args) {//line 1
int i= 1;//line 2
Object obj = new Object();//line 3
Memory mem = new Memory();//Line 4
mem.foo(obj);//Line 5
}//Line 9
private void foo(Object param) {//line 6
String str = param.toString();//line 7
System.out.println(str);
}//Line 8
}
[](
)字符串拼接操作
常量与常量的拼接结果在常量池,原理是编译期优化
常量池中不会存在相同内容的变量
只要其中有一个是变量,结果就在堆中。变量拼接的原理是 StringBuilder
如果拼接的结果调用 intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址
举例 1:
public static void test1() {
// 都是常量,前端编译期会进行代码优化
String s1 = "a" + "b" + "c";
String s2 = "abc";
// true,有上述可知,s1 和 s2 实际上指向字符串常量池中的同一个值
System.out.println(s1 == s2);
}
反编译为 class 文件后,会发现 String s1 = “abc”; 说明代码在编译期进行了优化
举例 2:
public static void test2() {
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4); // true 编译期优化
System.out.println(s3 == s5); // false s1 是变量,不能编译期优化
System.out.println(s3 == s6); // false s2 是变量,不能编译期优化
System.out.println(s3 == s7); // false s1、s2 都是变量
System.out.println(s5 == s6); // false s5、s6 不同的对象实例
System.out.println(s5 == s7); // false s5、s7 不同的对象实例
System.out.println(s6 == s7); // false s6、s7 不同的对象实例
String s8 = s6.intern();
System.out.println(s3 == s8); // true intern 之后,s8 和 s3 一样,指向字符串常量池中的"javaEEhadoop"
}
变量拼接原理:
当两个变量:String s1=“a”;String s2=“b”;相加时:其执行细节如下:
①StringBuilder s=new StringBuilder();
②s.append(“a”);
③s.append(“b”);
④s.toString();
举例 3:
public void test3(){
String s0 = "ab";
String s1 = "a";
String s2 = "b";
String s3 = s1 + s2;
System.out.println(s0 == s3); // false s3 指向对象实例,s0 指向字符串常量池中的"ab"
String s7 = "cd";
final String s4 = "c";
final String s5 = "d";
String s6 = s4 + s5;
System.out.println(s6 == s7); // true s4 和 s5 是 final 修饰的,编译期就能确定 s6 的值了
}
字符串拼接操作不一定使用的时 StringBuilder,如果使用 final 修饰,即为常量,会在编译器进行代码优化。如果不使用 final 修饰,即为变量,会通过 new StringBuilder 进行拼接。在实际开发中,能够使用 final 的,尽量使用。
举例 4:
字符串拼接操作性能对比:
public class Test{
public static void main(String[] args) {
int times = 40000;
long start = System.currentTimeMillis();
testString(times); // String 6963ms
//testStringBuilder(times); // StringBuilder 2ms
long end = System.currentTimeMillis();
System.out.println("String: " + (end-start) + "ms");
}
public static void testString(int times) {
String str = "";
评论