前言
- 话不多说直接进入正题
一、三道面试题
- Q1:如下代码一共创建几个对象?
String str = "a" + "b";
- A1:emmm,刷过面试题的肯定会这么回答:四个!因为String是final的,所以会创建
"a", "b", "ab"
三个String对象以及一个str对象,它指向"ab"这一个字符串
。我相信大多数人都是这么回答的,那么到底是不是呢?咱们以jdk1.8中jvm
的角度来验证下(会使用到字节码相关的知识点) - 使用jdk1.8解析:
1.新建java类并添加如下代码:
public class Test { public static void main(String[] args) { String str = "a" + "b"; } }
2.使用
javac
命令或idea中将它编译成class文件javac Test.java
3.使用
javap -c
命令进行反编译查看字节码指令, 如下图所示
由上可以看到,实际上创建的只有一个对象ab
, 如果说还要有一个,那就是一个存放在栈里的str
引用对象,所以在jdk1.8版本的jvm中,String str = "a" + "b"; 如果把引用对象也算进去的话,这里只创建了两个对象,如果不算引用对象的话,这里只创建了一个对象
-
Q2: 以下代码一共创建了几个对象?
String a = "a"; String b = "b"; String ab = a + b;
-
A2: emmm, 刷过面试题的又会说: 不算引用对象的话,有
"a", "b", "ab"
一共是3
个对象,算引用对象的话,有"a", "b", "ab",引用对象a,引用对象b,引用对象ab
一共是6
个对象。咱们也从jvm的角度来解析下 -
使用jdk1.8解析:
1.新建java类并添加如下代码:
public class Test { public static void main(String[] args) { String a = "a"; String b = "b"; String ab = a + b; } }
2.使用
javac
命令或idea中将它编译成class文件javac Test.java
3.使用
javap -c
命令进行反编译查看字节码指令, 如下图所示
由上可以看出,总共创建了
a, b
两个常量,后续new了一个StringBuild对象,String ab = “a” + “b”;这行代码使用的是StringBuild的append方法进行拼接的所以在此处,一共有6个对象,分别是"a", "b", 一个new出来的StringBuild对象,引用对象a, b, ab
。
- Q3: 以下代码一共创建了几个对象?
String str = new String("a" + "b" + "c");
- A3: 这次咱们不猜了,直接分析jvm如何做的
这里一共创建了两个对象以及一个str的引用对象
二、总结
- 由上可知,我们能发现jvm编译的几个特点:
- 我们在方法内部定义的变量名在jvm内部没有被用到
- 所有的字符串常量(类似于: “a” + “b”)的拼接,jvm都会把它优化,直接变成ab常量,所以中途不会创建"a", "b"两个对象。
- 所有的字符串引用变量的拼接,如下
jvm都会在底层创建一个StringBuild变量并使用它的append方法进行拼接String a = "a"; String b = "b"; String ab = a + b;