zoukankan      html  css  js  c++  java
  • 字符串在内存中的情况

    声明:今天偶然在csdn论坛上看到的一篇关于字符串内存中细节分析的帖子里有一条评论,觉得分析理解的比较好。特意copy过来,供自己学习参考,也给大家分享一下。

    首先要先了解JVM的内存模型
    JVM运行时数据区的内存模型由五部分组成:
    1 方法区
    2 堆
    3 JAVA栈
    4 PC寄存器
    5 本地方法栈

    String str = "abc"创建对象的过程
    1 首先在常量池中查找是否存在内容为"abc"字符串对象
    2 如果不存在则在常量池中创建"abc",并让str引用该对象
    3 如果存在则直接让str引用该对象

    至于"abc"是怎么保存,保存在哪?常量池属于类信息的一部分,而类信息反映到JVM内存模型中是对应存在于JVM内存模型的方法区,也就是说这个类信息中的常量池概念是存在于在方法区中,而方法区是在JVM内存模型中的堆中由JVM来分配的,所以"abc"可以说存在于堆中(而有些资料,为了把方法区的堆区别于JVM的堆,把方法区称为栈)。一般这种情况下,"abc"在编译时就被写入字节码中,所以class被加载时,JVM就为"abc"在常量池中分配内存,所以和静态区差不多。

    String str = new String("abc")创建实例的过程
    1 首先在堆中(不是常量池)创建一个指定的对象"abc",并让str引用指向该对象
    2 在字符串常量池中查看,是否存在内容为"abc"字符串对象
    3 若存在,则将new出来的字符串对象与字符串常量池中的对象联系起来
    4 若不存在,则在字符串常量池中创建一个内容为"abc"的字符串对象,并将堆中的对象与之联系起来
    intern 方法可以返回该字符串在常量池中的对象的引用,可以通过下面代码简单的测试

    Java code?
    1
    2
    3
    4
    5
    6
    7
    class StringTest {
        public static void main(String[] args) {
            String str1 = "abc";
            String str2 = new String("abc").intern();
            System.out.println(str1==str2);
        }
    }



    所以String str1 = "abc",str1引用的是常量池(方法区)的对象,而String str2 = new String("abc"),str2引用的是堆中的对象,所以内存地址不一样,但是内容一样,所以==为false,而equals是true
    而String str1 = "abc"; String str2 = "ab" + "c"; str1==str2是ture,是因为String str2 = "ab" + "c"会查找常量池中时候存在内容为"abc"字符串对象,如存在则直接让str2引用该对象,显然String str1 = "abc"的时候,上面说了,会在常量池中创建"abc"对象,所以str1引用该对象,str2也引用该对象,所以str1==str2
    而String str1 = "abc"; String str2 = "ab"; String str3 = str2 + "c"; str1==str3是false,是因为String str3 = str2 + "c"涉及到变量(不全是常量)的相加,所以会生成新的对象,其内部实现是先new一个StringBuilder,然后append(str2),append("c");然后让str3引用toString()返回的对象。LZ如果想了解更多的细节,可以自己查看反编译的代码,查看反编译代码可以用javap,即
    javap -c -verbose 要查看的类文件(.class不要)
    比如上面的代码的示例
    javac StringTest.java //编译
    javap -c -verbose StringTest //反编译

    说到java中堆、栈和常量池,首先还是看看他们各自存放的数据类型吧!

     堆:存放所有new出来的对象;栈:存放基本类型的变量数据和对象的引用(指针),对象(new出来的对象)本身并不存在栈中,而是存放在堆中或者常量池中(字符串常量对象存放在常量池中);常量池:存放基本类型常量和字符串常量。

    对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。

        而对于字符串来说,其对象的引用都是存储在栈中的,如果是编译期已经创建好(即指用双引号定义的)的就存储在常量池中,如果是运行期(new出来的对象)则存储在堆中。对于equals相等的字符串,在常量池中是只有一份的,在堆中则有多份。

  • 相关阅读:
    Set和Multiset 怎么用咧↓↓↓
    sql server 复习笔记2
    sql server 复习笔记1
    数据分析相关学习 -1 numpy
    复习2
    scrapy 4 学习 crawl spider
    scrapy3 中间件的使用
    scapy2 爬取全站,以及使用post请求
    复习1
    scrapy 学习笔记2 数据持久化
  • 原文地址:https://www.cnblogs.com/qingtianyu/p/3528352.html
Copyright © 2011-2022 走看看