引言
在这周的面试当中,我遇到了几个不是很清楚的题目,回家之后进行学习发现了一些比较有意思的事情,在这里记录一下
这周还发现了一个很有帮助的Java知识网站:Java 基础 - 面向对象 | Java 全栈知识体系
1.字符串和常量池
在这次面试当中遇到的一个原题就是
String i = "i"和new String("i")一样吗?如果不一样,为什么?
在面试的时候我因为之前没去研究过这个所以不知道怎么回答,于是我就随便写了个一样,前者隐式调用了构造器(什么JB,乱回答)
在面试结束之后我回去学习了一下,答案是这两个表达式其实是不一样的,这就涉及到了String和虚拟机了
首先我们打开String源码进行查看
这里我们看到String字符其实是一个final修饰的Object,final修饰符修饰一个类代表了这个类不能被继承,这里还使用final修饰了value这个char类型的数组(这里还会扩展出自JDK9之后底层改用byte数组实现,大致就是拉丁字符更省空间,如果在中文比较少的情况下是大概节省了一半空间的,这里可以具体去了解一下)
这里我们就可以知道String其实是一个不可变的常量,那么String i = "i"到底做了什么呢?
答案就是在Jvm虚拟机当中的方法池里有一个常量池,这里是阅读了<<深入理解JVM虚拟机>>这本书的第二部分之后看到的
String在常量池里找有没有这个字符串,如果没有则添加到常量池并且将当前引用指向字符串的地址
new String("i")则是先检查常量池,如果常量池有则新建一个对象并且拷贝字符,所以new String的内存地址是不在常量池的,如果常量池没有这个字符则向常量池添加这个字符再拷贝新建对象到方法堆里,也就是说无论如何都会新建一个对象.
之前也做过测试,如果有两个s1 , s2,他们都是字面赋值的同一个字符,那么他们的内存地址引用时一样的,也就是说返回的时true(这里只是验证,平时不推荐使用来对比引用对象),同样的字符字面赋值和new出来的String对象的内存地址是不一样的.
Integer的缓存池
在学习常量池的时候还发现一个比较有意思的事情,就是关于int类型的包装类型Integer在常量池里有IntegerCache缓存池(-128,127)
也就是说当Integer赋值为
Integer i = 127
Integer i1 = 127
类似于这种赋值,按理来说valueof两个int值是两个新的对象,但是有缓存池的存在所以这两个引用对象的内存地址是一样的,也就是说==返回的是true
但是如果使用new Integer的话那么就是新建一个对象了,不指向缓存池里的地址了.