一个例子

  1. public class TestString{
  2. public static void main(String[] args){
  3. String a = "a";
  4. String b = a+"b";
  5. String c = "ab";
  6. String d = "a" + "b";
  7. System.out.println(c == d); //true!!!!
  8. System.out.println(c == d.intern()); //true
  9. System.out.println(b == c); //false
  10. System.out.println(b.intern() == c); //true!!!
  11. System.out.println(b == c.intern()); //false
  12. System.out.println(b == d); //false
  13. }
  14. }

结果分析:

c==d是true,是因为d="a"+"b"是两个常量String的对象相加,返回的String对象就是常量String;

b==c是false,是因为b=a+“b”,java 重载了“+”,反编译java字节码可以发现“+”其实是调用了StringBuilder 所以使用了“+”其实是生成了一个新的对象;

b.intern() == c 是true, 因为,如果常量池中存在当前字符串,就会直接返回当前字符串;如果常量池中没有此字符串,会将此字符串放入常量池中后,再返回。

后续把上面的猜想挨着验证;

先编译:javac TestString.java;

在使用cfr-0.137.jar将java反编译:java -jar cfr-0.137.jar TestString.class --stringbuilder false ;
反编译结果如下:

  1. /*
  2. * Decompiled with CFR 0.137.
  3. */
  4. import java.io.PrintStream;
  5.  
  6. public class TestString {
  7. public static void main(String[] arrstring) {
  8. String string = "a";
  9. String string2 = new StringBuilder().append(string).append("b").toString();
  10. String string3 = "ab";
  11. String string4 = "ab";
  12. System.out.println(string3 == string4);
  13. System.out.println(string3 == string4.intern());
  14. System.out.println(string2 == string3);
  15. System.out.println(string2.intern() == string3);
  16. System.out.println(string2 == string3.intern());
  17. System.out.println(string2 == string4);
  18. }
  19. }

可以看到,两个字符串相加,如果其中一个不是常量字符串(即不是通过变量名引用的字符串如"LuoTiany"),那么编译器编译后,JVM执行就会通过new StringBuilder对象操作,如果在一个循环中,就会产生多个StringBuilder对象,所以字符串相加,尽量使用StringBuilder对象的append(异步)或StringBuffer对象的append(同步);

使用javap -c TestString.class反编译结果如下(javap反编译参数):

  1. Compiled from "TestString.java"
  2. public class TestString {
  3. public TestString();
  4. Code:
  5. 0: aload_0
  6. 1: invokespecial #1 // Method java/lang/Object."<init>":()V
  7. 4: return
  8.  
  9. public static void main(java.lang.String[]);
  10. Code:
  11. 0: ldc #2 // String a
  12. 2: astore_1
  13. 3: new #3 // class java/lang/StringBuilder
  14. 6: dup
  15. 7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
  16. 10: aload_1
  17. 11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  18. 14: ldc #6 // String b
  19. 16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  20. 19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  21. 22: astore_2
  22. 23: ldc #8 // String ab
  23. 25: astore_3
  24. 26: ldc #8 // String ab
  25. 28: astore 4
  26. 30: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
  27. 33: aload_3
  28. 34: aload 4
  29. 36: if_acmpne 43
  30. 39: iconst_1
  31. 40: goto 44
  32. 43: iconst_0
  33. 44: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
  34. 47: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
  35. 50: aload_3
  36. 51: aload 4
  37. 53: invokevirtual #11 // Method java/lang/String.intern:()Ljava/lang/String;
  38. 56: if_acmpne 63
  39. 59: iconst_1
  40. 60: goto 64
  41. 63: iconst_0
  42. 64: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
  43. 67: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
  44. 70: aload_2
  45. 71: aload_3
  46. 72: if_acmpne 79
  47. 75: iconst_1
  48. 76: goto 80
  49. 79: iconst_0
  50. 80: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
  51. 83: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
  52. 86: aload_2
  53. 87: invokevirtual #11 // Method java/lang/String.intern:()Ljava/lang/String;
  54. 90: aload_3
  55. 91: if_acmpne 98
  56. 94: iconst_1
  57. 95: goto 99
  58. 98: iconst_0
  59. 99: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
  60. 102: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
  61. 105: aload_2
  62. 106: aload_3
  63. 107: invokevirtual #11 // Method java/lang/String.intern:()Ljava/lang/String;
  64. 110: if_acmpne 117
  65. 113: iconst_1
  66. 114: goto 118
  67. 117: iconst_0
  68. 118: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
  69. 121: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
  70. 124: aload_2
  71. 125: aload 4
  72. 127: if_acmpne 134
  73. 130: iconst_1
  74. 131: goto 135
  75. 134: iconst_0
  76. 135: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
  77. 138: return
  78. }

上面如果看不懂,可以在这里找,javap编译后二进制指令代码详解:http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html#Post

JVM内存中的常量池的位置

  1. @Test
  2. public void constantPool(){
  3. List<String> list = new ArrayList<String>();
  4. int i=0;
  5. while(true){
  6. list.add(String.valueOf(i++).intern());
  7. }
  8. }

在执行的时候先设置VM启动参数:

在原来的VM options :-ea 后面追加-Xmx128m -Xms64m -Xmn32m -Xss16m -XX:-UseGCOverheadLimit;

这里的-XX:-UseGCOverheadLimit是关闭GC占用时间过长时报的异常,-Xmx等参数见:https://www.cnblogs.com/theRhyme/p/9120705.html

执行上面的单元测试,等了数十秒:

说明在Java8中,字符串常量池在JVM的堆中。参考:https://blog.csdn.net/u014039577/article/details/50377805

为什么String被设计为不可变?

https://www.cnblogs.com/wuchanming/p/9201103.html

  • 安全首要原因是安全,不仅仅体现在你的应用中,而且在JDK中,Java的类装载机制通过传递的参数(通常是类名)加载类,这些类名在类路径下,想象一下,假设String是可变的,一些人通过自定义类装载机制分分钟黑掉应用。如果没有了安全,Java不会走到今天
  • 性能 string不可变的设计出于性能考虑,当然背后的原理是string pool,当然string pool不可能使string类不可变,不可变的string更好的提高性能。
  • 线程安全当多线程访问时,不可变对象是线程安全的,不需要什么高深的逻辑解释,如果对象不可变,线程也不能改变它。

Java中String的intern方法,javap&cfr.jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置的更多相关文章

  1. JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】

    写在前面,欢迎大家关注小编的微信公众号!!谢谢大家!! 一.前言 String字符串在我们日常开发中最常用的,当然还有他的两个兄弟StringBuilder和StringBuilder.他三个的区别也 ...

  2. Java中String类的方法及说明

    String : 字符串类型 一.      String sc_sub = new String(c,3,2);    //      String sb_copy = new String(sb) ...

  3. 【转载】Java中String类的方法及说明

    转载自:http://www.cnblogs.com/YSO1983/archive/2009/12/07/1618564.html String : 字符串类型 一.      String sc_ ...

  4. java中String的.trim()方法

    该方法去除两边的空白符 原理: 看看源码实现 public String trim() { int len = value.length; ; char[] val = value; /* avoid ...

  5. java中String的一些方法

    1.public String(char[] c,begin,length). 从字符数组c的下标begin处开始,将长度为length的字符数组转换为字符串. begin与length可以省略,即将 ...

  6. JAVA中String类的方法(函数)总结--JAVA基础

    1.concat()方法,当参数为两字符串时,可实现字符串的连接: package cn.nxl123.www; public class Test { public static void main ...

  7. Java中String的split()方法的一些需要注意的地方

    public String[] split(String regex, int limit) split函数是用于使用特定的切割符(regex)来分隔字符串成一个字符串数组,这里我就不讨论第二个参数( ...

  8. Java中String的split()方法的一些疑问和试验

    http://tjuking.iteye.com/blog/1507855 和我想的还是不大一样,因为不知道源码也不知道具体是怎么实现的,我的理解如下: 当字符串只包含分隔符时,返回数组没有元素:当字 ...

  9. Java中String对象创建机制详解()

    一String 使用 private final char value来实现字符串存储 二Java中String的创建方法四种 三在深入了解String创建机制之前要先了解一个重要概念常量池Const ...

随机推荐

  1. 让MySql支持表情符号(MySQL中4字节utf8字符保存方法)

    UTF-8编码有可能是两个.三个.四个字节.Emoji表情是4个字节,而MySQL的utf8编码最多3个字节,所以数据插不进去. 解决方案:将编码从utf8转换成utf8mb4. 1. 修改my.in ...

  2. 2-Zookeeper、HA安装

    1.Zookeeper安装 1.解压 zookeeper 到安装目录中/opt/app/zookeeper 中. 2.在安装目录下创建data和logs两个目录用于存储数据和日志: cd /opt/a ...

  3. Spring Security数据库管理

    要实现数据库管理用户角色及权限,需要自定义用户登录功能,Spring Security已经为我们提供了接口UserDetailService.需要以下表: 用户表 角色表 权限表 用户角色关系表 权限 ...

  4. WPF简单实用方法(持续更新)

    1:点击退出提示框 MessageBoxResult result = MessageBox.Show("你真的要退出吗?", "", MessageBoxBu ...

  5. Android2.2+opencv3.1配置实现

    来实习什么都要自己干,不仅仅要写算法,还要再Android上面跑起来.... 弄了三天才搞好,就因为一点点失误!!! 第一步:安装Android Studio2.2    安装opencv3.1 下载 ...

  6. tornado项目注意点

    大体框架思想 如果你做的项目是偏向中小型的话,MTV或者MVC已经足够支撑起整个项目,而如果你做的项目比较大大话,或者说可能以后的业务量很大的话,那你就需要用到四层架构的思想了,那么我们就各自分析下俩 ...

  7. 启动tomcat时cmd窗口一闪而过

    在tomcat的安装目录下 双击startup.bat启动时cmd窗口一闪而过 1.在系统中查看配置JDK的环境变量是否正确 2.进入tomcat的安装目录 在启动tomcat时流程是:startup ...

  8. OpenGL Hello World

    ▶ OpenGL 的环境配置与第一个程序 ● CUDA 中自带 OpenGL 需要的头文件和库,直接拉进项目里边去就行 ● VS项目属性右键,属性,C/C++ 目录,包含目录,添加 CUDA 的头文件 ...

  9. userdel 用户名 出现“用户**目前已登录”

    userdel 用户名 出现“用户**目前已登录” 今天在删除用户账号的时候,发现一个奇怪现象,即: userdel: user newname is currently logged in 相关命令 ...

  10. SaltStack 和 Ansible 的简单比较

    https://blog.csdn.net/nqxqxq/article/details/76154847 https://www.cnblogs.com/lgeng/p/6567424.html   ...