网站封装,成全高清视频免费观看,工业设计公司收费标准,建设房地产网站目录
一、String的基本特性 二、String的内存分配
2.1、String内存分布图
三、字符串拼接操作 3.1、字符串拼接操作底层原理
3.2、拼接操作与append操作效率对比
四、intern()方法
4.1、intern()效率
五、StringTable的垃圾回收
一、String的基本特性
1、String字符…目录
一、String的基本特性 二、String的内存分配
2.1、String内存分布图
三、字符串拼接操作 3.1、字符串拼接操作底层原理
3.2、拼接操作与append操作效率对比
四、intern()方法
4.1、intern()效率
五、StringTable的垃圾回收
一、String的基本特性
1、String字符串使用一对引起表示
2、String声明为Final的不可被继承
3、String实现了Serializable接口表示字符串是支持序列化的。实现Comparable接口表示String可以比较大小。
4、String字符串在JDK8及以前内部定义了final char[] value用于存储字符串数据。jdk9时改为byte[]。
5、String代表不可变的字符串序列。①、当对字符串重新赋值时需要重写指定内存区域赋值不能使用原有的value进行赋值。②、当对现有的字符串进行连接操作时也需要重新指定内存区域赋值不能使用原有的value进行赋值。③、当调用String的replace()方法修改指定字符或字符串时也需要重新指定内存区域赋值不能使用原有的value进行赋值。
6、通过字面量的方式(区别于new)给一个字符串赋值此时的字符串值声明在字符串常量池中。
参考代码
public class StringTest {Testpublic void test1(){String s1 a;String s2 a;s2 b;System.out.println(s1 s2);//falseSystem.out.println(s1);//aSystem.out.println(s2);//b}Testpublic void test2(){String s1 a;String s2 a;s2 b;System.out.println(s1);//aSystem.out.println(s2);//ab}Testpublic void test3(){String s1 a;String s2 s1.replace(a,b);System.out.println(s1);//aSystem.out.println(s2);//b}
}
面试题
public class StringTest02 {String s1 new String(hello);char[] chars {t,o,m};public void change(String s1,char chars[]){s1 test ok;chars[0] a;}public static void main(String[] args) {StringTest02 str new StringTest02();str.change(str.s1,str.chars);System.out.println(str.s1);//”hello“System.out.println(str.chars);//”aom“}
}7、字符串常量池是不会存储相同内容的字符串。
①、String的String Pool是一个固定大小的Hashtable默认值大小长度是1009.如果放进String Pool的String非常多就会造成Hash冲突严重从而导致链表会很长而链表长了后直接会造成的影响就是调用String.intern时性能会大幅度下降。
参考代码
public class StringTest04 {public static void main(String[] args) {try {FileWriter fileWriter new FileWriter(hello.txt);for (int i 0; i 100000; i) {int length (int) (Math.random() * (10) 1);fileWriter.write(getString(length) \n);}fileWriter.close();} catch (IOException e) {throw new RuntimeException(e);}}public static String getString(int length){String str ;for (int i 0; i length; i) {int num (int) (Math.random() * (90 - 65 1) 65) (int) (Math.random() * 2) * 32;str (char)num;}return str;}
}public class StringTest03 {public static void main(String[] args) {//参数设置-XX:StringTableSize1009
// System.out.println(String参数设置开始);
// try {
// Thread.sleep(100000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }BufferedReader bufferedReader null;try {bufferedReader new BufferedReader(new FileReader(hello.txt));long start System.currentTimeMillis();String data;while ((data bufferedReader.readLine()) ! null){data.intern();}long end System.currentTimeMillis();System.out.println(花费的时间为 (end - start));//参数1009.时间91ms。参数1000009时间35ms} catch (IOException e) {throw new RuntimeException(e);}finally {if (bufferedReader ! null){try {bufferedReader.close();} catch (IOException e) {throw new RuntimeException(e);}}}}}
②、使用-XX:StringTableSize可设置StringTable的长度。
③、在jdk6中的StringTable的是固定的就是1009的长度所以如果常量池中的字符串过多就会导致效率下降很快。StringTableSize设置没有要求。
④、在jdk7中StringTable的默认长度是60013jdk8及以后1009是设置的最小值。
以jdk8测试 二、String的内存分配
1、Java语言中有八大基本数据类型和特殊的String类型这些类型为了使它们在运行过程中速度更快更节省内存都提供了一种常量池概念。
2、常量池类似一个Java系统级别提供缓存。8种基本数据类型的常量池都是系统协调的String类型的常量池比较特殊。 ①、直接使用双引号声明出来的String对象会直接存储在常量池中。 ②、不使用双引号声明的String对象可以使用String提供的intern()方法。
3、Java6及以前字符串常量池存放在永久代中。
4、Java7中将字符串常量池的位置调整到Java堆中。 ①、所有的字符串都保存在堆中和其他普通对象一样这样可以在进行调优应用时仅需要调整堆大小就可以了。 ②、字符串常量池概念原本使用的比较多但改动后可以重新考虑在Java7中使用String.intern()
5、Java8元空间字符串常量在堆。
2.1、String内存分布图 三、字符串拼接操作
1、常量与常量的拼接结果是在常量池原理是编译期优化。
2、常量池中不会存在相同内容的常量。
3、只要其中一个是变量结果就在堆中。变量的拼接的原理是StringBuilder。
4、如果拼接的结果调用intern()方法则主动将常量池中还没有的字符串对象放入池中并返回此对象地址。
参考代码 Testpublic void test1(){String s1 a b c;String s2 abc;System.out.println(s1 s2);//trueSystem.out.println(s1.equals(s2));//true}Testpublic void test2(){String s1 javaee;String s2 hadoop;String s3 javaeehadoop;String s4 javaee hadoop;//编译期优化//拼接字符串的前后出现变量相当于在堆空间中new String(),String s5 s1 hadoop;String s6 javaee s2;String s7 s1 s2;System.out.println(s3 s4);//trueSystem.out.println(s3 s5);//falseSystem.out.println(s3 s6);//falseSystem.out.println(s3 s7);//falseSystem.out.println(s5 s6);//falseSystem.out.println(s5 s7);//falseSystem.out.println(s6 s7);//false//intern()判断字符串常量池中是否存在javaeehadoop值有就返回该值地址没有就重新加载一份。String s8 s6.intern();System.out.println(s3 s8);//true} 3.1、字符串拼接操作底层原理
参考代码 Testpublic void test3(){String s1 a;String s2 b;String s3 ab;/*** s1 s2执行步骤* ①、StringBuilder s new StringBuilder();* ②、s.append(a)* ③、s.append(b)* s.toString() --- 约等于 new String(ab);*/String s4 s1 s2;System.out.println(s3 s4);//false}Testpublic void test4(){/*** 字符串拼接操作不一定使用StringBuilder()* 如拼接符号左右两边都是字符串常量或常量引用则仍然使用编译期优化* 针对于final修饰的类、方法、基本数据类型引用数据类型的量的结构时能使用final时建议使用*/final String s1 a;final String s2 b;String s3 ab;String s4 s1 s2;System.out.println(s3 s4);//true}
3.2、拼接操作与append操作效率对比
参考代码
Testpublic void test5(){/***通过StringBuilder的append()的方式添加字符串的效率要远高于字符串拼接* ①、StringBuilder的append()方式只需要创建一个StringBuilder对象而字符串拼接则需要创建多个StringBuilder和String对象* ②、使用String的字符串拼接方式内存中创建了较多的StringBuilder和String对象内存占用更大如垃圾回收效率要更频繁* 优化在基本确定要添加的字符串的长度不高于某个限定值highlevel可以使用构造器new StringBuilder(参数)*/long start System.currentTimeMillis();method1(10000);long end System.currentTimeMillis();System.out.println(method1花费时间为 (end - start));//89long start1 System.currentTimeMillis();method2(10000);long end1 System.currentTimeMillis();System.out.println(method2花费时间为 (end1 - start1));//0}public void method1(int highLevel){String str ;for (int i 0; i highLevel; i) {str str a;}}public void method2(int highLevel){StringBuilder stringBuilder new StringBuilder();for (int i 0; i highLevel; i) {stringBuilder stringBuilder.append(a);}}
四、intern()方法
如果不是双引号声明的String对象可以使用String提供的intern():intern方法会从字符串常量池中查询当前字符串是否存在如不存在就会将当前字符串放入常量池中。
public class StringTest07 {//以jdk8为例public static void main(String[] args) {String s new String(1);s.intern();//调用此方法之前常量池中已经有“1String s1 1;System.out.println(s s1);//false//s3变量的记录地址为new String(”11“)但在常量池中没有创建的”11“String s3 new String(1) new String(1);s3.intern();//该方法执行完就生成11但没有在常量池中创建”11“而是创建一个指向堆空间中new String(”11“)的地址String s4 11;//使用的是上行代码生成的”11“ --》即常量池中生成的”11“的地址System.out.println(s3 s4);//true}
} 总结在jdk6中如果串池中有就返回已有的串池中的对象的地址如果没有就是将这个对象复制一份放入串池并返回这个对象的地址。从jdk7起如果串池中有就返回已有的串池中的对象的地址如果没有就是将这个对象的引用地址复制一份放入串池并返回串池中的引用地址。
4.1、intern()效率
参考代码
public class StringTest08 {static final int MAX_COUNT 1000 * 10000;static final String[] arr new String[MAX_COUNT];public static void main(String[] args) {int[] data {1, 2, 3, 4, 5, 6, 7, 8, 9};long start System.currentTimeMillis();for (int i 0; i MAX_COUNT; i) {//arr[i] new String(String.valueOf(data[i % data.length]));arr[i] new String(String.valueOf(data[i % data.length])).intern();}long end System.currentTimeMillis();System.out.println(花费的时间为: (end - start));try {Thread.sleep(100000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.gc();}
}结论对于程序中大量存在的字符串尤其其中存在很多重复字符串时使用intern()可以节省很多内存空间。
五、StringTable的垃圾回收
参考代码
参数设置-Xms15m -Xmx15m -XX:PrintStringTableStatistics -XX:PrintGCDetails
public class StringTest09 {public static void main(String[] args) {for (int i 0; i 1000000; i) {String.valueOf(i).intern();}}
}