字符串常量池在jdk升级过程中发生了一些变化

      在JDK1.6中,它在方法区中,属于“永久代”.

在JDK1.7中,它被移除方法区,放在java堆中。

在JDK1.8中,取消了“永久代”,将常量池放在元空间,与堆独立

jdk1.6中,intern()方法会把首次遇到的字符串示例复制到永久代中,返回的也是永久代中这个字符串实例的引用

jdk1.6以后,对于实例,intern()方法不会再复制实例,只是在常量池中记录首次出现的实例引用,对于字符串仍然是加入字符串常量

比如下面这段代码,这段代码在常量池加入的直接是“ab”的引用

String s = new String("a")+new String("b")
s.intern()

创建字符串分析

以下转自 https://blog.csdn.net/u013366617/article/details/83618361

1.直接使用双引号创建字符串

 判断这个常量是否存在于常量池,
  如果存在,
   判断这个常量是存在的引用还是常量,
    如果是引用,返回引用地址指向的堆空间对象,
    如果是常量,则直接返回常量池常量,
  如果不存在,
    在常量池中创建该常量,并返回此常量

String a1 = "AA";//在常量池上创建常量AA
String a2 = "AA";//直接返回已经存在的常量AA
System.out.println(a1 == a2); //true String a3 = new String("AA"); //在堆上创建对象AA
a3.intern(); //在常量池上创建对象AA的引用
String a4 = "AA"; //常量池上存在引用AA,直接返回该引用指向的堆空间对象,即a3
System.out.println(a3 == a4); //false 这里一开始写错了
注意!!!对上面的做个小小的解释
String a3 = new String("AA"); //在堆上创建对象AA
a3.intern();
String a4 = "AA";
System.out.println(a3 == a4); //false
对比
String a3 = new String("AA").intern(); //在堆上创建对象AA
String a4 = "AA";
System.out.println(a3 == a4); //true
是不是感觉很奇怪
原因是a3.intern()确实返回的是常量池里的引用,但是不是a3本身,a3本身还是实例对象的引用
如果这样写
String a3 = new String("AA"); //在堆上创建对象AA
String a = a3.intern();
String a4 = "AA";
System.out.println(a == a4); //true

2.new String创建字符串

 首先在堆上创建对象(无论堆上是否存在相同字面量的对象),
 然后判断常量池上是否存在字符串的字面量,
  如果不存在
   在常量池上创建常量
  如果存在
   不做任何操作

String a1 = new String("AA");
String a2 = new String("AA");
System.out.println(a1 == a2); //false //如果常量池上不存在常量AA,也不存在引用AA,则创建常量AA
String a1 = new String("AA");
System.out.println(a1 == a1.intern()); //false

3.双引号相加

 判断这两个常量、相加后的常量在常量池上是否存在
  如果不存在
   则在常量池上创建相应的常量
  如果存在
   判断这个常量是存在的引用还是常量,
    如果是引用,返回引用地址指向的堆空间对象,
    如果是常量,则直接返回常量池常量,

String a1 = "AA" + "BB";//在常量池上创建常量AA、BB和AABB,并返回AABB

//常量池上存在常量AABB
String a2 = "AABB";
String a3 = "AA" + "BB";
System.out.println(a2 == a3); //true //常量池上存在引用AABB
String a4 = new String("AA") + new String("BB"); //在堆上创建对象AA、BB和AABB,在常量池上创建常量AA和BB
a4.intern();
String a5 = "AA" + "BB";
System.out.println(a4 == a5); //true

4.两个new String相加

 首先会创建这两个对象以及相加后的对象
 然后判断常量池中是否存在这两个对象的字面量常量
  如果存在
   不做任何操作
  如果不存在
   则在常量池上创建对应常量

//常量AA不存在,所以第一步在常量池中创建了常量AA
String a2 = new String("AA") + new String("BB");
String a3 = new String("A")+new String("A"); //创建对象AA
System.out.println(a3 == a3.intern()); //false //只在堆上创建AABB对象,没有在常量池中创建常量AABB
String a2 = new String("AA") + new String("BB");
System.out.println(a2 == a2.intern()); //true

5.双引号字符串与new String字符串

 首先创建两个对象,一个是new String的对象,一个是相加后的对象
 然后判断双引号常量与new String的字面量在常量池是否存在
  如果存在
   不做操作
  如果不存在
   则在常量池上创建对象的常量

String a1 = "AABB";
String a2 = "AA" + new String("BB");
System.out.println(a1 == a2.intern());//true
System.out.println(a2 == a2.intern()); //false

二.String.intern()分析

 判断这个常量是否存在于常量池。
  如果存在
   判断存在内容是引用还是常量,
    如果是引用,
     返回引用地址指向堆空间对象,
    如果是常量,
     直接返回常量池常量
  如果不存在,
   将当前对象引用复制到常量池,并且返回的是当前对象的引用

String a1 = "AA";
System.out.println(a1 == a1.intern()); //true
String a2 = new String("B") + new String("B");
a2.intern();
String a3 = new String("B") + new String("B");
System.out.println(a2 == a3.intern());//true
System.out.println(a3 == a3.intern());//false
String a4 = new String("C") + new String("C");
System.out.println(a4 == a4.intern()); //true

三.总结

1.只在常量池上创建常量

String a1 = "AA";

2.只在堆上创建对象

String a2 = new String("A") + new String("A");

3.在堆上创建对象,在常量池上创建常量

String a3 = new String("AA");

4.在堆上创建对象,在常量池上创建引用

String a4 = new String("A") + new String("A");//只在堆上创建对象AA
a4.intern();//将该对象AA的引用保存到常量池上

5.在堆上创建对象,在常量池上创建常量,在常量池上创建引用(不可能)

String a5 = new String("A") + new String("A");//只在堆上创建对象
a5.intern();//在常量池上创建引用
String a6 = "AA";//此时不会再在常量池上创建常量AA,而是将a5的引用返回给a6
System.out.println(a5 == a6); //true

练习

String aa = "AA";//设置常量AA到常量池
String bb = "BB";//设置常量BB到常量池
String ccdd = "CC"+"DD";//设置常量CCDD到常量池
String neeff = new String("EE")+new String("FF");//设置EE和FF到常量池。并且添加EE、FF和EEFF对象到堆
String aabb = aa+bb;//添加AABB对象到堆
String gghh = "GG"+new String("HH");//设置GG和HH常量到常量池,设置HH和GGHH对象到堆
//aa.intern();//啥事都不做,返回AA常量
//ccdd.intern();//啥事都不做,返回CCDD常量
//neeff.intern();//添加EEFF对象的引用到常量池,并返回EEFF对象
//aabb.intern();//添加AABB对象的引用到常量池,并返回AABB对象
//gghh.intern();//添加GGHH对象的引用到常量池,并返回GGHH对象
System.out.println(aa.intern()==aa); //true
System.out.println(neeff.intern()=="EEFF");//true
System.out.println("EEFF"==neeff);//true
String nccdd = new String("CCDD");
System.out.println(ccdd==nccdd);//false
System.out.println(ccdd==nccdd.intern());//true
System.out.println(aabb.intern()==aabb);//true
System.out.println(gghh==gghh.intern());//true

jdk1.8下字符串常量的判断,String.intern()分析的更多相关文章

  1. 字符串常量池和String.intern()方法在jdk1.6、1.7、1.8中的变化

    字符串常量池也是运行时常量池 jdk1.6中,它是在方法区中,属于“永久代” jdk1.7中,它被移除方法区,放在java堆中 jdk1.8中,取消了“永久代”,将常量池放在元空间,与堆独立了 pub ...

  2. Knowledge Point 20180309 字符串常量池与String,intern()

    引言 什么都先不说,先看下面这个引入的例子: public static void test4(){ String str1 = new String("SEU") + new S ...

  3. Java String类相关知识梳理(含字符串常量池(String Pool)知识)

    目录 1. String类是什么 1.1 定义 1.2 类结构 1.3 所在的包 2. String类的底层数据结构 3. 关于 intern() 方法(重点) 3.1 作用 3.2 字符串常量池(S ...

  4. 常量池之String.intern()方法

    JDK7将String常量池从Perm区移动到了Java Heap区.在JDK1.6中,intern方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中的实例.但是在JDK1.7以后,Str ...

  5. 关于jvm中的常量池和String.intern()理解

    1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...

  6. Java中String字符串常量池总结

    最近到广州某建站互联网公司面试,当时面试官问假设有两个字符串String a="abc",String b = "abc";问输出a==b是true还是fals ...

  7. String:字符串常量池

    String:字符串常量池 作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池: 字 ...

  8. 对于JVM中方法区,永久代,元空间以及字符串常量池的迁移和string.intern方法

    在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法信息(如字节码,栈和变量大小),运行时常量池,已确定的符号引用和虚方法表. 在过去(当自定义类加载器使用不普 ...

  9. JAVA String对象和字符串常量的关系解析

    JAVA String对象和字符串常量的关系解析 1 字符串内部列表 JAVA中所有的对象都存放在堆里面,包括String对象.字符串常量保存在JAVA的.class文件的常量池中,在编译期就确定好了 ...

随机推荐

  1. Eclipse配置C++环境

    由于实在不想用(界面太丑,超级强迫症),前段时间JAVA一直用eclipse,感觉这个IDE非常友好,看上去很舒服,下载的时候发现有C++版本,于是折腾了一会儿,谷歌上发现好多教程,但是大部分比较老, ...

  2. 升级lamp中php5.6到php7.0过程

    升级过程我就直接摘录博友,http://www.tangshuang.net/1765.html,几乎问题和解决办法都是参照他的,所以我也就不另外写了.谢谢!! 周末看了一下php7的一些情况,被其强 ...

  3. 容斥原理&&莫比乌斯专题

    A题:A - Eddy's爱好   HDU - 2204 具体思路:如果是求n中,为平方数的有多少个,那么答案肯定是sqrt(n),同理,如果是三次根号的话,那么答案肯定是n的三分之一次方.然后继续按 ...

  4. 存储过程简单Demo

    --创建存储过程 delimiter // create procedure p1() begin end // --调用存储过程 call p1(); --删除存储过程 drop procedure ...

  5. mysql备份的 三种方式【转】

    备份的本质就是将数据集另存一个副本,但是原数据会不停的发生变化,所以利用备份只能回复到数据变化之前的数据.那变化之后的呢?所以制定一个好的备份策略很重要. 一.备份的目的 做灾难恢复:对损坏的数据进行 ...

  6. avalonJS-源码阅读(一)

    写angularJS源码阅读系列的时候,写的太垃圾了.一个月后看,真心不忍直视,以后有机会的话得重写.这次写avalonJS,希望能在代码架构层面多些一点,少上源码.多写思路. avalon暴露句柄方 ...

  7. 转载: 开源整理:Android App新手指引开源控件

    http://blog.coderclock.com/2017/05/22/android/open-source-android-app-guide-view-library/ 开源整理:Andro ...

  8. ASP .NET Core 2.0 MVC 发布到 IIS 上以后 无法下载apk等格式的文件

    ASP .NET Core MVC 发布到  IIS 上以后 无法下载apk等格式的文件 使用.NET Core MVC创建了一个站点,其他文件可以下载,但是后来又需求,就把手机端的apk合适的文件上 ...

  9. POJ 3286 How many 0's(数位DP模板)

    题目链接:http://poj.org/problem?id=3286 题目大意: 输入n,m,求[n,m]的所有数字中,0出现的总数是多少,前导零不算. 解题思路: 模板题,设dp[pos][num ...

  10. babel转换不了有些es6

    bable只转换新语法 不支持新的全局变量如promise async等等,可以使用babel-polyfilll来兼容