各位老铁们,大家好,今天由我来为大家分享dj音乐网站模板源码分享,以及dj音乐资源网站的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
1String类的底层演变
JDK8的字符串存储在char类型的数组里面,在java中,一个char类型占两个字节。但是很多时候,一个字符只需要一个字节就可存储,比如各种字母什么的,两个字节存储势必会浪费空间,JDK9的一个优化就在这,内存的优化,所以JDK9之后字符串改成byte类型数组进行存储。\n\nprivatefinalbytecoder;\n在JDK9的String类中,新增了一个属性coder,它是一个编码格式的标识,使用LATIN1还是UTF16,这个是在String生成的时候自动确定的,如果字符串中都是能用LATIN1编码表示,那coder的值就是0,否则就是UTF16编码,coder的值就是1。\n\n可以看到JDK9在这方面的优化,在较多情况下不包含那些奇奇怪怪的字符的时候,足以应付,而这个空间却小了1byte,实现了String空间的压缩。
2String常量池的演变
2.1StringTable变化
String的StringPool是一个固定大小的Hashtable。\n\n在jdk6中,StringTable的长度固定为1009。\n如果放进StringPool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用intern()时性能会大幅下降。\n\n从jdk7起,StringTable的长度默认值是60013。\n\n使用-XX:StringTableSize可设置StringTable的长度。\n在jdk8之前,对StringTableSize的设置没有最小限制。\njdk8开始,StringTable可设置的最小值是1009。\n\n\n验证:\n通过jps命令查看进程号\n使用jinfo-flagStringTableSize进程号查看StringTable大小
2.2内存位置变化
Java6及以前,字符串常量池存放在永久代。\n\nJava7开始,字符串常量池的位置调整到Java堆内。\n所有的字符串都保存在堆(Heap)中,和其他普通对象一样,这样在进行调优应用时仅需要调整堆大小就可以了。
官网说明
https://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html34;main&34;main&34;hello&34;world&2<hello>\n2astore_1\n3ldc4<java/lang/StringBuilder>\n9dup\n10invokespecial6<java/lang/StringBuilder.append>\n17aload_2\n18invokevirtual7<java/lang/StringBuilder.toString>\n24astore_3\n25getstatic9<java/io/PrintStream.println>\n32return
使用JDK9编译后字节码:
0ldc3<world>\n5astore_2\n6aload_1\n7aload_2\n8invokedynamic0>\n13astore_3\n14getstatic6<java/io/PrintStream.println>\n21return
结论:
JDK8及之前,字符串变量的拼接,底层使用的是StringBuilder对象,利用append方法进行拼接。\n(注:jdk1.4之前使用StringBuffer)\n\n\nJDK9以后的编译器已经改成使用动态指令invokedynamic,\n\t调用StringConcatFactory.makeConcatWithConstants方法进行字符串拼接优化。\n
3.2核心方法
makeConcatWithConstants方法在StringConcatFactory类中定义。\n\n\tmakeConcatWithConstants内部调用了doStringConcat,\n而doStringConcat方法则调用了generate方法来生成MethodHandle;\ngenerate根据不同的STRATEGY来生成MethodHandle,这些STRATEGY(策略)有\nBC_SB(等价于JDK8的优化方式)\nBC_SB_SIZED\nBC_SB_SIZED_EXACT\nMH_SB_SIZED\nMH_SB_SIZED_EXACT\nMH_INLINE_SIZED_EXACT(默认)\n\n前五种策略本质还是用StringBuilder的实现,而默认的策略MH_INLINE_SIZED_EXACT是直接使用字节数组来操作,并且字节数组长度预先计算好,可以减少字符串复制操作。\n\n可以通过添加JVM参数来改变默认的策略,例如将策略改为BC_SB\n\t-Djava.lang.invoke.stringConcat=BC_SB\n\t-Djava.lang.invoke.stringConcat.debug=true\n
源码:
==makeConcatWithConstants内部调用了doStringConcat方法==
==doStringConcat方法则调用了generate方法来生成MethodHandle==
==generate根据不同的STRATEGY来生成MethodHandle==
==这些STRATEGY(策略)分别是==
privateenumStrategy{\n/**\n*Bytecodegenerator,callinginto{@linkjava.lang.StringBuilder}.\n*/\nBC_SB,\n\n/**\n*Bytecodegenerator,callinginto{@linkjava.lang.StringBuilder};\n*buttryingtoestimatetherequiredstorage.\n*/\nBC_SB_SIZED,\n\n/**\n*Bytecodegenerator,callinginto{@linkjava.lang.StringBuilder};\n*butcomputingtherequiredstorageexactly.\n*/\nBC_SB_SIZED_EXACT,\n\n/**\n*MethodHandle-basedgenerator,thatintheendcallsinto{@linkjava.lang.StringBuilder}.\n*Thisstrategyalsotriestoestimatetherequiredstorage.\n*/\nMH_SB_SIZED,\n\n/**\n*MethodHandle-basedgenerator,thatintheendcallsinto{@linkjava.lang.StringBuilder}.\n*Thisstrategyalsoestimatetherequiredstorageexactly.\n*/\nMH_SB_SIZED_EXACT,\n\n/**\n*MethodHandle-basedgenerator,thatconstructsitsownbyte[]arrayfrom\n*thearguments.Itcomputestherequiredstorageexactly.\n*/\nMH_INLINE_SIZED_EXACT\n}
==默认的策略MH_INLINE_SIZED_EXACT==
3.3常见笔试题
/*\n产生2个字符串对象:字符串常量池中一个,堆内存中一个。\n*/\nStrings=newString(&34;);\n\n\n\n/*\n产生1个字符串对象:常量池中的&34;。\n代码在编译阶段会优化为Strings=&34;;\n*/\nStrings=&34;+&34;+&34;;\n\n\n\n/*\n5个字符串对象\n常量池:&34;,&34;\n堆内存:new方式的&34;,new方式的&34;,new方式的&34;\n注意:常量池中不会产生&34;\n*/\nStrings=newString(&34;)+newString(&34;);\n\n\n\n/*\njdk8及之前创建3个字符串对象:\n常量池:&34;,&34;\n堆中:new&34;\n\njdk9之后创建2个字符串对象:\n常量池:&34;\n堆中:new&34;\n*/\nStrings1=&34;;\nStrings2=&34;+&34;+s1;\n
4intern()方法的演变
4.1intern()方法调用区别
publicclassStringDemo5{\npublicstaticvoidmain(String[]args){\nStrings1=newString(&34;);\nStrings2=&34;;\nSystem.out.println(s1==s2);//fasle\n\n\n//intern()方法从常量池中取出&34;对象\nStrings1=newString(&34;).intern();\nStrings2=&34;;\nSystem.out.println(s1==s2);//true\n\n/*\n从常量池中取出和s1内容相同的&34;对象,此时常量池中没有&34;对象。\n\n如果常量池中没有该字符串对象:\njdk6及之前,intern()方法会创建新的字符串对象,放入常量池并返回新的地址。\njdk7及之后,intern()方法会将调用者对象的地址放入常量池,并返回调用者对象地址。\n*/\nStrings1=newString(&34;)+newString(&34;);\ns1.intern();\nStrings2=&34;;\nSystem.out.println(s1==s2);//jdk6false;jdk7之后true\n}\n\n}
4.2intern()方法总结
intern()方法将这个字符串对象尝试放入常量池中,并返回地址。\n\njdk1.6中:\n如果池中有,则不会放入,返回已有的池中的对象的地址。\n如果池中没有,则把此对象重新创建一份,放入池中,并返回池中新的对象地址。\n\njdk1.7起:\n如果池中有,则不会放入,返回已有的池中的对象的地址。\n如果池中没有,则把此对象的引用地址复制一份,放入池中,并返回池中的引用地址。
如果你还想了解更多这方面的信息,记得收藏关注本站。
