字符串常量池在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. 搭建zookeeper单机版以及简单命令的使用

    1:创建目录 #数据目录dataDir=/opt/hadoop/zookeeper-3.3.5-cdh3u5/data#日志目录dataLogDir=/opt/hadoop/zookeeper-3.3 ...

  2. (转载) 天梯赛 L2-018. 多项式A除以B

    题目链接 题目描述 这仍然是一道关于A/B的题,只不过A和B都换成了多项式.你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数. 输入格式: 输入分两行,每行给出一个非零多项式,先给出 ...

  3. Hive笔记之collect_list/collect_set(列转行)

    Hive中collect相关的函数有collect_list和collect_set. 它们都是将分组中的某列转为一个数组返回,不同的是collect_list不去重而collect_set去重. 做 ...

  4. Java并发编程(2) AbstractQueuedSynchronizer的设计与实现

    一 前言 上一篇分析AQS的内部结构,其中有介绍AQS是什么,以及它的内部结构的组成,那么今天就来分析下前面说的内部结构在AQS中的具体作用(主要在具体实现中体现). 二 AQS的接口和简单示例 上篇 ...

  5. 彻底搞懂字符编码(unicode,mbcs,utf-8,utf-16,utf-32,big endian,little endian...)[转]

    最近有一些朋友常问我一些乱码的问题,和他们交流过程中,发现这个编码的相关知识还真是杂乱不堪,不少人对一些知识理解似乎也有些偏差,网上百度, google的内容,也有不少以讹传讹,根本就是错误的(例如说 ...

  6. jQuery-对标签元素 文本操作-属性操作-文档的操作

    一.对标签元素文本操作 1.1 对标签中内容的操作 // js var div1 = document.getElementById("div1"); div1.innerText ...

  7. 19 Error handling and Go go语言错误处理

    Error handling and Go go语言错误处理 12 July 2011 Introduction If you have written any Go code you have pr ...

  8. 数据库-mysql函数

    一:MySQL中提供了许多内置函数 CHAR_LENGTH(str) 返回值为字符串str 的长度,长度的单位为字符.一个多字节字符算作一个单字符. 对于一个包含五个二字节字符集, LENGTH()返 ...

  9. Nginx - 压缩模块

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

  10. jenkins主从服务器部署

    当服务器为linux系统但也有部分ios代码,此时就需要添加一个从jenkins以便编译ios代码.或者需要多个job同时编译这时就需要搭建主从服务器. 1.主(master)节点安装jenkins ...