原创 Java字符串究竟存储在哪里

发布时间:2021-06-24 15:26:04 浏览 503 来源:猿笔记 作者:可乐可乐可

    #字符串究竟存在哪里,-**如果使用常量的方式:该对象将被存储在常量池(永久代)**,-**如果使用new的方式,该对象将被存储在堆**,**下面的代码揭示了情况,-使用**常量**的形式,-使用**new**的方式,-即使**调用了常量创建的对象的方法**“比如Java的字符串常量池,各位先看这个String中神奇的方法,这个方法是一个**native的方法****如果常量池中存在当前字符串就会直接返回当前字符串.如果常量池中没有此字符串再返回**\t//这里使用常量池存在的字符串\t//这里构建一个常量池不存在的字符串对象


    #主题列表:juejin,github,smartblue,cyanosis,channing-cyan,fancy,hydrogen,condensed-night-purple,greenwillow,v-green,vue-pro,healer-readable,mk-cute,jzman,geek-black,awesome-green,qklhk-chocolate

    #投稿主题:

    theme:hydrogen

    highlight:

    本文来自——可乐可乐可乐,作者主页链接:【可乐可乐可乐个人主页】(

    早上看群友讨论,Java字符串在哪里的话题出现了。大致目睹了虚拟机的鸡开始感兴趣,研究整理了这篇博文

    #字符串存在于哪里

    以下是每个人都同意的一个总结:

    -* *如果使用常量,对象将存储在常量池中(永久生成)* *

    -* *如果使用new,对象将存储在堆中* *

    * *以下代码揭示了这种情况:* *

    ——用* *不变* *的形式,这是同一个对象

    -对不同的对象使用**新* *的方法

    -即使* *调用了常量创建的对象的方法* *,对象也不会改变:描述是一个对象,不是一组数组。

    `java

    publicclassTestString{

    publicstaticvoidmain(String[]args){

    Stringa="Aa";

    Stringb="Aa";

    System.out.println(a==b);

    Stringc=newString("Aa");

    System.out.println(b==c);

    b.charAt(0);

    Stringd=newString("Aa");

    System.out.println(d==c);

    System.out.println(b==a);

    }

    }

    /**

    true

    false

    false

    true

    Processfinishedwithexitcode0

    **/

    `

    这就是简单的规则。希望在这里看到就够了。

    不过对比具体实现会觉得很精彩,比如Java的字符串常量池和intern方法,下面会详细介绍

    #深入了解

    在我们开始之前,让我们来看看这个字符串中的神奇方法

    `String.intem();`

    `java

    /**

    *Returnsacanonicalrepresentationforthestringobject.

    *

    *Apoolofstrings,initiallyempty,ismaintainedprivatelybythe

    *classString.

    *

    *Whentheinternmethodisinvoked,ifthepoolalreadycontainsa

    *stringequaltothisStringobjectasdeterminedby

    *the{@link#equals(Object)}method,thenthestringfromthepoolis

    *returned.Otherwise,thisStringobjectisaddedtothe

    *poolandareferencetothisStringobjectisreturned.

    *

    *Itfollowsthatforanytwostringssandt,

    *s.intern()==t.intern()istrue

    *ifandonlyifs.equals(t)istrue.

    *

    *Allliteralstringsandstring-valuedconstantexpressionsare

    *interned.Stringliteralsaredefinedinsection3.10.5ofthe

    *TheJavaLanguageSpecification.

    *

    *@returnastringthathasthesamecontentsasthisstring,butis

    *guaranteedtobefromapoolofuniquestrings.

    */

    publicnativeStringintern();

    `

    这个方法是* *原生方法* *,但是评论很明确。”* *如果常量池中存在当前字符串,则直接返回。如果不在常量池中,则放入常量池中,然后返回* *”。

    先记住这个绝妙的方法,建议你思考一下这个逻辑。

    我们尝试使用这种实习方法,并判断实习方法的作用

    `java

    publicstaticvoidmain(String[]args){

    \t//在这里,使用常量池中存在的字符串来构建字符串对象

    Strings=newString("1");

    s.intern();

    Strings2="1";

    System.out.println(s==s2);

    \t//在常量池不存在的地方构建一个字符串对象。

    Strings3=newString("1")+newString("1");

    s3.intern();

    Strings4="11";

    System.out.println(s3==s4);

    }

    `

    代码解释:

    -s和s1的目的是比较当常数池* *具有值* *时,由**new方法生成的字符串* *和由常数* *生成的字符串* *是否是对象。

    -s3和s4的目的是在常数池* *不具有值* *时,比较**new方法生成的字符串* *和**intern后使用常数* *生成的字符串是否是对象。

    如果您有两个JDK环境:1.6和1.7

    你会得到两个截然不同的答案:

    JDK1.6:`falsefalse`

    JDK1.7:`falsetrue`

    #然后了解JDK1.6和JDK1.7中常量池的区别

    ###先看看JDK1.6

    在**JDK1.6中,* *,* *恒池是一个独立的区域* *;在jdk6中,常量池放置在**Perm区域,与正常的JAVAHeap区域完全分开。

    有些人可能不是很懂

    让我们换一种说法:

    * *字符串类型“String”存储在常量池* *,常量池和Java堆是两个不同的部分* *。

    也就是说,

    -* *存储在常量池和存储在堆中,实现不同。**

    -**常量池默认4M,所以存在消耗尽,抛出`java.lang.OutOfMemoryError:PermGenspace`**

    -调用实习方法。如果常量池中不存在该字符串,将在方法区域创建一个新的字符串并返回

    ###来到JDK1.7

    JDK1.7中取消了这个叫做perm的区域,常量池就是堆。* *常量池中的字符串对象和堆中的字符串对象存在于同一区域。

    在jdk7版本中,字符串常量池已经从Perm区域* *移动到了普通的JavaHeap区域。

    为什么要搬家?* *彼尔姆面积太小。* *当然,根据新闻,**jdk8已经直接取消了Perm区,创建了一个新的meta区* *

作者信息

可乐可乐可 [等级:3] 后端研发工程师
发布了 10 篇专栏 · 获得点赞 36 · 获得阅读 1746

相关推荐 更多