最近在顺着”Java工程师成神之路”里列的条目一个一个看下来,看到final关键字那部分时,发现一个看似简单的关键字其实也是很多很多的内容在里面的,能跟对象类型、JVM内存结构关联在一起。
栗子
public class Test {
public static void main(String[] args) {
String a = "helloworld";
final String b = "hello";
String d = "hello";
String c = b + "world";
String e = d + "world";
System.out.println((a == c));
System.out.println((a == e));
}
}
上面的例子看起来很简单,同学们可以先自己判断一下结果是多少
|
|
|
|
|
|
|
|
true
false
下面我来解释下为什么会是true、false。
首先我们要知道JVM内存模型中有栈、堆(常量池)、方法区(运行时常量池)以及其他一些部分。
- String a = “helloworld”在编译时生成的对象本身是在字符串常量池中。
- final String b = “hello” 因为有final 所以是final常量,存放于方法区中。
- String c = b + “world” 中的 b 是个直接引用常量,编译期间会直接优化成 String c = “helloworld” ,所以其实是跟 a 指向常量池中同一个字符串。
- String e = d + “world” 中的 d 是变量,无法提前优化。编译时生成于堆中。
最后补充一下字符串的创建过程:
- “” 引号创建的字符串在字符串池中
- new 创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则导致浪费池的空间)
还有顺便说一个知识点,就是当 Integer 的数值在 -128 到 127 之间时,会有一个拆箱的操作,变成 int 也就是基本类型。