String和new String

这几天在学习jvm内存结构的时候,发现很多文章关于运行时常量池这个概念没有说清,这里自己总结了一下,有不当之处欢迎指正;以下是参考文章:

  1. JDK1.8关于运行时常量池, 字符串常量池的要点
  2. Java内存管理

尤其是看了第一篇之后,没想到一个简简单单的String还有这么东西,所以自己也是简单测了一下,加深对jvm的理解。
测试之前先简单说明一下概念:

  • 首先是方法区和永久代,目前有三大Java虚拟机:HotSpot,oracle JRockit,IBM J9。目前使用最多的就是HotSqot,而另外两个是不存在永久代这种说法的,所以可以认为方法区和永久代的关系就类似于类和对象的概念,永久代即是对方法区的实现,在jdk1.8之后,方法区的实现由永久代变为元空间;
  • 然后是字符串常量池,字符串常量池属于运行时常量池的一部分,而运行时常量池是属于方法区的,但是在jdk1.7中字符串常量池被单独从方法区中拿到了堆中, 运行时常量池其他部分任然在方法区中;1.8中方法区被元空间取而代之,拿到了本地内存中,此时,字符串常量池任然在堆中
  • intern()方法:在<深入理解Java虚拟机>一书中关于该方法的解释是:
    String.intern()是一个Native方法,它的作用是:如果字符常量池中已经包含一个等于此String对象的字符串,则返回常量池中字符串的引用,否则,将新的字符串放入常量池,并返回新字符串的引用。

以下是相关测试

  1. String 和new String的区别
String s1 = "123";  
String s2 = new String("123"); 
System.out.println(s1 == s2); //false

这里很好理解,a是存储在字符串常量池中,而b是new出来的,存放在堆中;注意,虽然上面说了字符串常量池被单独拿到了堆中,但是他和堆中存放的对象任然是隔离的;

  1. new String到底创建了几个对象
String s1 = new String("ab");
String s2 = "ab";
System.out.println(s1 == s2 ); // false
System.out.println(s1.intern() == s2 ); // true

通过该例可以看出new String创建了两个对象,先是在字符串常量池中创建了"ab"常量即s1.intern(),然后在堆中开辟了一块内存存储ab变量即s1;这里有个误区,我在看第一篇参考文章底下的评论的时候,有人认为既然new String创建了两个对象,那么第4行的结果应该是true;这句话前半段没错,new String虽然创建了两个对象,但是实际上只会指向堆中的那个对象,而常量池中的对象是通过intern()指向的;

  1. String + String创建了几个对象
String s1 = "a"+"b";
String s2 = "ab";
System.out.println(s2 == s1); // true

这里创建了1个对象,jvm编译阶段过编译器优化后会把字符串常量直接合并成"ab",所有创建对象时最多会在常量池中创建1个对象。

  1. new String+new String
	String s1 = "aabb";
	String s2 = new String("aa")+new String("bb");
	System.out.println(s1 == s2); //false
	System.out.println(s1 == s2.intern()); //true

此时第二行创建过程中不会在字符串常量池中生成aabb字符串,看以下论证:

String s1 = "a";
String s2 = "b";
String s3 = s1 + s2;
String s4 = new String("ab");

System.out.println(s4.intern() == s3);  // false
System.out.println(s3 == s4); // false

如果在"a"+"b"拼接的过程中,在字符串常量中产生了"ab",那么第一行的输出应该为true而不是false,所以可以的到new String(“a”)+new String(“b”)的创建过程并不会在常量池中生成"ab";

但是,该论证是有缺陷的,s1和s2虽然是常量,但是在s3中是变量,相当于new出来的,所以第二行输出为false,因为两个都可以看做是new出来的,这样一来也能解释第一行的输出,因为一个在堆中,一个在字符串常量池中,自然为false;
关于这部分论证可以看下这两篇文章JAVA中String.intern的理解new String(“123”) 创建了几个对象?

猜你喜欢

转载自blog.csdn.net/Wyunpeng/article/details/121848465