首先看这样一个面试题

// StringTable [ "a", "b" ,"ab" ]  hashtable 结构,不能扩容
public class Demo1_22 {
// 常量池中的信息,都会被加载到运行时常量池中, 这时 a b ab 都是常量池中的符号,还没有变为 java 字符串对象
// ldc #2 会把 a 符号变为 "a" 字符串对象
// ldc #3 会把 b 符号变为 "b" 字符串对象
// ldc #4 会把 ab 符号变为 "ab" 字符串对象 public static void main(String[] args) {
String s1 = "a"; // 懒惰的
String s2 = "b";
String s3 = "ab";
String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString() new String("ab")
String s5 = "a" + "b"; // javac 在编译期间的优化,结果已经在编译期确定为ab
System.out.println(s3 == s4); // false
System.out.println(s3 == s5); // true
}
}

我们从字节码的角度来分析结果

首先反编译该类代字节码,输入命令:

javap -v Demo1_22.class // -v显示详细信息

得到结果:

Classfile /D:/work_folder/java_studying/idea_workspace/jvm/out/production/jvm/cn/itcast/jvm/t1/stringtable/Demo1_22.class
Last modified 2019-12-8; size 1039 bytes
MD5 checksum 9efed67948c7dacf9ddb854ca18f8c2b
Compiled from "Demo1_22.java"
public class cn.itcast.jvm.t1.stringtable.Demo1_22
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #12.#36 // java/lang/Object."<init>":()V
#2 = String #37 // a
#3 = String #38 // b
#4 = String #39 // ab
#5 = Class #40 // java/lang/StringBuilder
#6 = Methodref #5.#36 // java/lang/StringBuilder."<init>":()V
#7 = Methodref #5.#41 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#8 = Methodref #5.#42 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#9 = Fieldref #43.#44 // java/lang/System.out:Ljava/io/PrintStream;
#10 = Methodref #45.#46 // java/io/PrintStream.println:(Z)V
#11 = Class #47 // cn/itcast/jvm/t1/stringtable/Demo1_22
#12 = Class #48 // java/lang/Object
#13 = Utf8 <init>
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 LocalVariableTable
#18 = Utf8 this
#19 = Utf8 Lcn/itcast/jvm/t1/stringtable/Demo1_22;
#20 = Utf8 main
#21 = Utf8 ([Ljava/lang/String;)V
#22 = Utf8 args
#23 = Utf8 [Ljava/lang/String;
#24 = Utf8 s1
#25 = Utf8 Ljava/lang/String;
#26 = Utf8 s2
#27 = Utf8 s3
#28 = Utf8 s4
#29 = Utf8 s5
#30 = Utf8 StackMapTable
#31 = Class #23 // "[Ljava/lang/String;"
#32 = Class #49 // java/lang/String
#33 = Class #50 // java/io/PrintStream
#34 = Utf8 SourceFile
#35 = Utf8 Demo1_22.java
#36 = NameAndType #13:#14 // "<init>":()V
#37 = Utf8 a
#38 = Utf8 b
#39 = Utf8 ab
#40 = Utf8 java/lang/StringBuilder
#41 = NameAndType #51:#52 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#42 = NameAndType #53:#54 // toString:()Ljava/lang/String;
#43 = Class #55 // java/lang/System
#44 = NameAndType #56:#57 // out:Ljava/io/PrintStream;
#45 = Class #50 // java/io/PrintStream
#46 = NameAndType #58:#59 // println:(Z)V
#47 = Utf8 cn/itcast/jvm/t1/stringtable/Demo1_22
#48 = Utf8 java/lang/Object
#49 = Utf8 java/lang/String
#50 = Utf8 java/io/PrintStream
#51 = Utf8 append
#52 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#53 = Utf8 toString
#54 = Utf8 ()Ljava/lang/String;
#55 = Utf8 java/lang/System
#56 = Utf8 out
#57 = Utf8 Ljava/io/PrintStream;
#58 = Utf8 println
#59 = Utf8 (Z)V
{
public cn.itcast.jvm.t1.stringtable.Demo1_22();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 4: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/itcast/jvm/t1/stringtable/Demo1_22; public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=6, args_size=1
0: ldc #2 // String a
2: astore_1
3: ldc #3 // String b
5: astore_2
6: ldc #4 // String ab
8: astore_3
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
16: aload_1
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: astore 4
29: ldc #4 // String ab
31: astore 5
33: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
36: aload_3
37: aload 4
39: if_acmpne 46
42: iconst_1
43: goto 47
46: iconst_0
47: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
50: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
53: aload_3
54: aload 5
56: if_acmpne 63
59: iconst_1
60: goto 64
63: iconst_0
64: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
67: return
LineNumberTable:
line 11: 0
line 12: 3
line 13: 6
line 14: 9
line 15: 29
line 16: 33
line 17: 50
line 18: 67
LocalVariableTable:
Start Length Slot Name Signature
0 68 0 args [Ljava/lang/String;
3 65 1 s1 Ljava/lang/String;
6 62 2 s2 Ljava/lang/String;
9 59 3 s3 Ljava/lang/String;
29 39 4 s4 Ljava/lang/String;
33 35 5 s5 Ljava/lang/String;
StackMapTable: number_of_entries = 4
frame_type = 255 /* full_frame */
offset_delta = 46
locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, c
lass java/lang/String ]
stack = [ class java/io/PrintStream ]
frame_type = 255 /* full_frame */
offset_delta = 0
locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, c
lass java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 79 /* same_locals_1_stack_item */
stack = [ class java/io/PrintStream ]
frame_type = 255 /* full_frame */
offset_delta = 0
locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, c
lass java/lang/String ]
stack = [ class java/io/PrintStream, int ]
}
SourceFile: "Demo1_22.java"

我们从中摘取最重要的一段:

 Code:
stack=3, locals=6, args_size=1
0: ldc #2 // String a
2: astore_1
3: ldc #3 // String b
5: astore_2
6: ldc #4 // String ab
8: astore_3
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
16: aload_1
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: astore 4
29: ldc #4 // String ab
31: astore 5

上面每句的意思可参照jvm指令手册去进行阅读

     0: ldc           #2                  // String a
ldc 把常量池中的项压入栈,即在Constant pool中找到#2,然后将其压入栈。也就是String a
astore_1 // astore_1 将引用类型或returnAddress类型值存入局部变量1
也就是LocalVariableTable中的这一行
3 65 1 s1 Ljava/lang/String;

其他类似,

在索引9的位置:

   9: new           #5                  // class java/lang/StringBuilder

这 就是创建了一个StringBuilder对象,

 13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V

""

StringTable的更多相关文章

  1. ue4 StringTable

    StringTable 用法很简单可以参考 https://blog.csdn.net/u012801153/article/details/80393531 这里只说说上面文章中没提到的小技巧  T ...

  2. JVM 专题十六:StringTable

    1. String的基本特性 String:字符串,使用一对""引起来表示. String声明为final的,不可被继承. String实现了Serializable接口:表示字符 ...

  3. StringTable结构以及基本调优

    StringTable底层实现类似于HashTable,由数组和链表组成,数组又称为桶数组.比如有这样一段代码: public class Demo4 { public static void mai ...

  4. 【JVM之内存与垃圾回收篇】StringTable

    StringTable String的基本特性 String:字符串,使用一对 "" 引起来表示 String s1 = "Nemo"; // 字面量的定义方式 ...

  5. JVM系列之:String.intern和stringTable

    目录 简介 intern简介 intern和字符串字面量常量 分析intern返回的String对象 分析实际的问题 G1中的去重功能 总结 简介 StringTable是什么?它和String.in ...

  6. 看了这篇文章,我搞懂了StringTable

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 String应该是Java ...

  7. JVM字符串常量池StringTable

    String的基本特性 String:字符串,使用一对""引起来表示. String sl = "hello"://字面量的定义方式: String s2 = ...

  8. 第 13 章 StringTable详解

    目录 第 13 章 StringTable 1.String 的基本特性 1.1.String 概述 1.2.String 的基本特征 1.3.String 的底层结构 2.String 的内存分配 ...

  9. JVM 中的StringTable

    是什么 字符串常量池是 JVM 中的一个重要结构,用于存储JVM运行时产生的字符串.在JDK7之前在方法区中,存储的是字符串常量.而字符串常量池在 JDK7 开始移入堆中,随之而来的是除了存储字符串常 ...

随机推荐

  1. asp.net core流式上传大文件

    asp.net core流式上传大文件 首先需要明确一点就是使用流式上传和使用IFormFile在效率上没有太大的差异,IFormFile的缺点主要是客户端上传过来的文件首先会缓存在服务器内存中,任何 ...

  2. 获取Object对象属性的方法,Reflect.ownKeys, Object.getOwnPropertyNames,Object.getOwnPropertySymbols,Object.keys,for in

    let triangle={ a:1, b:2, c:3 } function coloTriangle(){ this.color='red'; } coloTriangle.prototype=t ...

  3. Elasticsearch的快照备份

    该文档适用于备份使用NAS的仓库类型.所有Elasticsearch集群中的服务通过挂载NAS目录来存放备份快照数据. 1.创建备份仓库 创建一个仓库名称:backup curl -H "C ...

  4. mysql 无法连接提示 Authentication plugin 'caching_sha2_password' cannot be loaded

    mysql 无法连接提示 Authentication plugin 'caching_sha2_password' cannot be loaded 可能是密码没有设置或者,密码设置类型不符,可参考 ...

  5. MySQL5.7 安装和配置环境变量

    安装 1.下载安装包 官网地址:https://dev.mysql.com/downloads/mysql/ 2.选择 Custom,自定义 3.根据自己系统选择 x64还是x86,然后点击第一个箭头 ...

  6. Linux shell 中断循环语句

    无限循环: 循环有限的生命,他们跳出来,一旦条件是 false 还是 false 取决于循环. 由于所需的条件是不符合一个循环可能永远持续下去.永远不会终止执行一个循环执行无限次数.出于这个原因,这样 ...

  7. Linux文件服务管理之nfs

    NFS(Network File System)即网络文件系统, 是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源. 在NFS的应用中,本地NFS的客户端应 ...

  8. WTL 9.0的变化 - atlctrls.h

    atlctrls.h中是对控件的封装. 第1249行增加: void GetMargins(UINT& nLeft, UINT& nRight) const { ATLASSERT(: ...

  9. dedecms手机站和PC站共用同一数据库的方法

    我们知道搜索引擎建议将手机站和PC站分开,虽然自适应可以适配不同的终端,但单独建独立的m站可能权重和排名更好,因为移动端的竞争度不同甚至更低.代码更精简.蜘蛛抓取更顺畅,所以要单独建手机站比较好.那么 ...

  10. 微信公众平台iPhone版内测开始了

    5月9日晚些时候自媒体人收到了微信公众平台iPhone版的内测邀请,微信公众平台iPhone版可在手机上写图文,快速查看并回复粉丝消息.留言和赞赏,新建群发.查看群发历史和今日数据,这些功能很实用了, ...