Java中String的intern方法,javap&cfr.jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置
一个例子
- public class TestString{
- public static void main(String[] args){
- String a = "a";
- String b = a+"b";
- String c = "ab";
- String d = "a" + "b";
- System.out.println(c == d); //true!!!!
- System.out.println(c == d.intern()); //true
- System.out.println(b == c); //false
- System.out.println(b.intern() == c); //true!!!
- System.out.println(b == c.intern()); //false
- System.out.println(b == d); //false
- }
- }
结果分析:
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 ;
反编译结果如下:
- /*
- * Decompiled with CFR 0.137.
- */
- import java.io.PrintStream;
- public class TestString {
- public static void main(String[] arrstring) {
- String string = "a";
- String string2 = new StringBuilder().append(string).append("b").toString();
- String string3 = "ab";
- String string4 = "ab";
- System.out.println(string3 == string4);
- System.out.println(string3 == string4.intern());
- System.out.println(string2 == string3);
- System.out.println(string2.intern() == string3);
- System.out.println(string2 == string3.intern());
- System.out.println(string2 == string4);
- }
- }
可以看到,两个字符串相加,如果其中一个不是常量字符串(即不是通过变量名引用的字符串如"LuoTiany"),那么编译器编译后,JVM执行就会通过new StringBuilder对象操作,如果在一个循环中,就会产生多个StringBuilder对象,所以字符串相加,尽量使用StringBuilder对象的append(异步)或StringBuffer对象的append(同步);
使用javap -c TestString.class反编译结果如下(javap反编译参数):
- Compiled from "TestString.java"
- public class TestString {
- public TestString();
- Code:
- 0: aload_0
- 1: invokespecial #1 // Method java/lang/Object."<init>":()V
- 4: return
- public static void main(java.lang.String[]);
- Code:
- 0: ldc #2 // String a
- 2: astore_1
- 3: new #3 // class java/lang/StringBuilder
- 6: dup
- 7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
- 10: aload_1
- 11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
- 14: ldc #6 // String b
- 16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
- 19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
- 22: astore_2
- 23: ldc #8 // String ab
- 25: astore_3
- 26: ldc #8 // String ab
- 28: astore 4
- 30: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
- 33: aload_3
- 34: aload 4
- 36: if_acmpne 43
- 39: iconst_1
- 40: goto 44
- 43: iconst_0
- 44: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
- 47: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
- 50: aload_3
- 51: aload 4
- 53: invokevirtual #11 // Method java/lang/String.intern:()Ljava/lang/String;
- 56: if_acmpne 63
- 59: iconst_1
- 60: goto 64
- 63: iconst_0
- 64: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
- 67: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
- 70: aload_2
- 71: aload_3
- 72: if_acmpne 79
- 75: iconst_1
- 76: goto 80
- 79: iconst_0
- 80: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
- 83: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
- 86: aload_2
- 87: invokevirtual #11 // Method java/lang/String.intern:()Ljava/lang/String;
- 90: aload_3
- 91: if_acmpne 98
- 94: iconst_1
- 95: goto 99
- 98: iconst_0
- 99: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
- 102: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
- 105: aload_2
- 106: aload_3
- 107: invokevirtual #11 // Method java/lang/String.intern:()Ljava/lang/String;
- 110: if_acmpne 117
- 113: iconst_1
- 114: goto 118
- 117: iconst_0
- 118: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
- 121: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
- 124: aload_2
- 125: aload 4
- 127: if_acmpne 134
- 130: iconst_1
- 131: goto 135
- 134: iconst_0
- 135: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
- 138: return
- }
上面如果看不懂,可以在这里找,javap编译后二进制指令代码详解:http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html#Post
JVM内存中的常量池的位置
- @Test
- public void constantPool(){
- List<String> list = new ArrayList<String>();
- int i=0;
- while(true){
- list.add(String.valueOf(i++).intern());
- }
- }
在执行的时候先设置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常量池的位置的更多相关文章
- JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】
写在前面,欢迎大家关注小编的微信公众号!!谢谢大家!! 一.前言 String字符串在我们日常开发中最常用的,当然还有他的两个兄弟StringBuilder和StringBuilder.他三个的区别也 ...
- Java中String类的方法及说明
String : 字符串类型 一. String sc_sub = new String(c,3,2); // String sb_copy = new String(sb) ...
- 【转载】Java中String类的方法及说明
转载自:http://www.cnblogs.com/YSO1983/archive/2009/12/07/1618564.html String : 字符串类型 一. String sc_ ...
- java中String的.trim()方法
该方法去除两边的空白符 原理: 看看源码实现 public String trim() { int len = value.length; ; char[] val = value; /* avoid ...
- java中String的一些方法
1.public String(char[] c,begin,length). 从字符数组c的下标begin处开始,将长度为length的字符数组转换为字符串. begin与length可以省略,即将 ...
- JAVA中String类的方法(函数)总结--JAVA基础
1.concat()方法,当参数为两字符串时,可实现字符串的连接: package cn.nxl123.www; public class Test { public static void main ...
- Java中String的split()方法的一些需要注意的地方
public String[] split(String regex, int limit) split函数是用于使用特定的切割符(regex)来分隔字符串成一个字符串数组,这里我就不讨论第二个参数( ...
- Java中String的split()方法的一些疑问和试验
http://tjuking.iteye.com/blog/1507855 和我想的还是不大一样,因为不知道源码也不知道具体是怎么实现的,我的理解如下: 当字符串只包含分隔符时,返回数组没有元素:当字 ...
- Java中String对象创建机制详解()
一String 使用 private final char value来实现字符串存储 二Java中String的创建方法四种 三在深入了解String创建机制之前要先了解一个重要概念常量池Const ...
随机推荐
- AS导入项目报错:Plugin with id 'com.android.application' not found.
从github或第三方Demo中获取的项目导入到AndroidStudio中报错Plugin with id 'com.android.application' not found.:今天导入一个讯飞 ...
- Android最新版支付宝支付集成
上次集成支付宝支付已经很久了,今天写东西用到了支付宝支付,就大致写一下流程: 去蚂蚁金服下载最新版的Android&IOS端SDK 全部文档 -- 资源下载 -- App支付客户端 下载后解压 ...
- pip 国内源
pip install django -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com pip in ...
- StringBuffer 清除内容
在开发的时候,经常使用StringBuffer来进行字符串的拼接.如果反复的做字符串拼接时,有时需要清空Stringbuffer中的内容,然后再拼接新的字符串信息. StringBuffer提供了以下 ...
- spring 之 factory-bean & factory-method
这两者常常是一起出现的,或者说他们经常是一起被使用的.但是其实是分为了两种情况: 1 同时使用factory-bean 和 factory-method 如果,我们在一个bean 元素上同时配置 fa ...
- 关于 Container ,Injection
1.容器的历史 容器概念始于 1979 年提出的 UNIX chroot,它是一个 UNIX 操作系统的系统调用,将一个进程及其子进程的根目录改变到文件系统中的一个新位置,让这些进程只能访问到这个新的 ...
- addEventListener 的事件冒泡
语法 target.addEventListener(type, listener, useCapture); target 文档节点.document.window 或 XMLHttpRequest ...
- day06-单表查询
1.单表查询的语法 SELECT 字段1,字段2... FROM 表名 WHERE 条件 GROUP BY field HAVING 筛选 ORDER BY field LIMIT 限制条数 2.关键 ...
- 排序NB三人组
排序NB三人组 快速排序,堆排序,归并排序 1.快速排序 方法其实很简单:分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”.先从右往左找一个小于6的数,再从左往 ...
- BBS--后台管理页面,编辑文章,xss攻击
1 1.对文章进行增删改查 # 后台管理url re_path(r'^cn_backend/$', views.cn_backend, name='cn_backend'), re_path(r'^c ...