字符串常量池在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. 2.批处理内部命令之REM 和::

    REM为注释命令,一般用来给程序加上注解,该命令后的内容不被执行,但能回显. 另外, :: 也可以起到rem 的注释作用, 而且更简洁有效; 但有两点需要注意: 1. 任何以冒号:开头的字符行, 在批 ...

  2. phpcm nginx 伪静态文件

    rewrite ^/show-([0-9]+)-([0-9]+)-([0-9]+).html /index.php?m=content&c=index&a=show&catid ...

  3. HDU 3065 病毒侵袭持续中 (AC自动机)

    题目链接 Problem Description 小t非常感谢大家帮忙解决了他的上一个问题.然而病毒侵袭持续中.在小t的不懈努力下,他发现了网路中的"万恶之源".这是一个庞大的病毒 ...

  4. Jenkins远程调度Shell命令

    http://blog.csdn.net/fireofjava/article/details/40624353 Jenkins服务器为Win7版本,需要远程调用CentOS服务器上Shell脚本,然 ...

  5. PostgreSQL内核分析——BTree索引

    文中附图参考至<PostgreSQL数据库内核分析> (一)概念描述 B+树是一种索引数据结构,其一个特征在于非叶子节点用于描述索引,而叶子节点指向具体的数据存储位置.在PostgreSQ ...

  6. asp.net操作word 配置在IIS上出现的问题

    异常: 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件失败,原因是出现以下错误: 80070005 拒绝访问. (异常来自 ...

  7. Jenkins忘记用户名密码

    一.进入C盘.jenkins配置文件中找到config.xml 需要删除一下内容: <useSecurity>true</useSecurity> <authorizat ...

  8. Nginx - 压缩模块

    1. 前言 在 Nginx 中与网页压缩相关的模块有两个:一个是 HttpGzipModule,另一个是 HttpGzipStaticModule.前者用于启用在文件传输过程中使用 gzip 压缩,而 ...

  9. 制作macOS10.12系列的系统镜像文件

    制作macOS10.12系列的系统镜像文件步骤,过程也比较简单,十来个命令.以10.12.6为例,首先,在苹果商店下载系统安装包APP,或者网上下载后把安装APP复制到  应用程序  文件夹. 然后打 ...

  10. java基础75 xpth技术(网页知识)

    1.xpth技术 1.1.xpath的作用 主要用于快速获取所需的节点对象. list<Node> selectNodes("xpath");  查询多个节点对象    ...