面试题之Java创建几个String对象,五星推荐(却字符串常量池底层实现原理)

String s=new String("abc");
String s1="abc";
String s2=new String("abc");

面试题:请问上面的代码创建了几个String对象呢?


0、这涉及到JVM中String的机制,当你new一个String时,总会在堆中新建一个对象,然后String的引用指向这个对象


1、接着马上会检查String pool(字符串池)中有没有和这个字符串内容("abc")一样的字符串,没有的话,还会将此字符串对象加入到String pool中,即在字符串池中创建一个对象


2、当你直接用String a = "abc",这样去声明一个字符串的时候,JVM先检查字符串常量池里有没有 abc 这个字符串对象,有的话直接指向此字符串,没有的话在先在运行时常量池中增加这个字符串,然后再指向这个对象


3、这样的话,答案是一共创建了3个对象,堆中2个对象,字符串常量池中1个对象,new的时候调用的String的构造方法,而该构造方法接受的还是一个String对象

4、字符串池在哪?
答:字符串属于字面量,所以字符串池曾经位于运行时常量池中
a、运行时常量池在JDK1.6及之前版本在JVM中是方法区的一部分,而在HotSpot虚拟机中方法区是放在了”永久代(Permanent Generation)”。所以运行时常量池也是在永久代的(HotSpot虚拟机把方法区合并到了堆里,起名叫永久代)
b、注意:JDK1.7及之后版本的JVM已经将字符串常量池从方法区中移了出来,在Java 堆(Heap)中开辟了一块区域存放字符串池,此时运行时常量池还在方法区,也就是HotSpot的永久代中

 

5、字符串常量池与运行时常量池之间的关系是什么?文中怎么一会一个概念呢?再次强调一下概念!!

在JDK1.7之前运行时常量池逻辑上包含字符串常量池,并存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代

在JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池是被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot虚拟机中的永久代

在JDK1.8 hotspot虚拟机中移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace) 

 

6、字符串常量池,底层实现是什么?JVM是怎么去找对应的对象呢,假设字符串池中有100个对象,当你去用字面量的形式创建一个对象的,JVM是否是将当前对象做了一个遍历呢?

总结一下:

字符串常量池在每个VM中只有一份,存放的是字符串常量的引用值。
字符串常量池——string pool,也叫做string literal pool。
字符串池里的内容是在类加载完成,经过验证,准备阶段之后在堆中生成字符串实例对象,然后将该字符串对象实例的引用值存到string pool中。
string pool中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的

 

7、对于两个声明的字符串使用 " + " 拼接, 因为JVM的优化,会将拼接后的结果放入常量池.但是两个声明的字符串不会,(String s = “abc”+ “def”, 会直接生成“abcdef"字符串常量 而不把 “abc” "def"放进常量池)

 

8、番外篇,几种常量池傻傻分不清楚

Java中的常量池分为三种类型:

  • 类文件中常量池(The Constant Pool),也叫静态常量池
  • 运行时常量池(The Run-Time Constant Pool)
  • String常量池

 

9、常量池底层其实也是类似用HashMap的结构来存储数据,所以需要根据具体的场景合理的设置这个值,那么key是什么、value又是什么?这个答案在哪?

 

 

参考文章:

https://www.cnblogs.com/ydpvictor/archive/2012/09/09/2677260.html

 

你可能感兴趣的:(面试(综合))