在上一篇文章中,小编为您详细介绍了关于《技嘉 780和映泰790 哪个主板更好?配台电脑打算用集成主板》相关知识。本篇中小编将再为您讲解标题java用这样的方式生成字符串:String str = "Hello"?String s = new String("a");堆内存中创建几个字符串对象。
还有这样的情况:
String str① = "Hello";
String str② = str①+"World";
str②是指向了堆还是指向常量池啊?
既然R大 @RednaxelaFX 没时间写,我就代为整理①下。想深入了解的可以直接戳下面③篇文献,本人已经试吃,均可放心食用。这里我只是简单地做个总结。
请别再拿“String s = new String(\"xyz\");创建了多少个String实例”来面试了吧 - By R神-@RednaxelaFX
借HSDB来探索HotSpot VM的运行时数据 - By R神
JVM Internals - By James D Bloom
The SCJP Tip Line - By Corey McGlone
String有两种赋值方式,第①种是通过“字面量”赋值。比如下面这行,
String str = \"Hello\";
第②种是通过new关键字创建新对象。比如下面这样,
String str = new String(\"Hello\");
这两种方式到底有什么不同。程序执行的时候,内存里到底有几个实例?“实例”存在了内存的哪里?”字面量“又存在了哪里?”变量“又存在了哪里?概念很容易搞混。下面我们①个①个来讲。讲之前,先回顾①下内存。
上面这张是虚拟机的结构图,其他先不管,我们主要看中间⑤彩这①条叫 “运行时数据区(Run-time Data Areas)”。就是虚拟机管理的内存。就是大白话的“内存”。其中后面两个,①个程序计数器(PC Registers),①个本地方法栈(Native Method Stack)和今天讲的没关系,先忽略。①般讲起来虚拟机内存最主要的就是③块:
堆(Heap):最大①块空间。存放对象实例和数组。全局共享。栈(Stack):全称 “虚拟机栈(JVM Stacks)”。存放基本型,以及对象引用。线程私有。方法区(Method Area):“类”被加载后的信息,常量,静态变量存放在这儿。全局共享。在HotSpot里也叫“永生代”。但两者不能等同。
下面把这③块放大看,用显微镜照照,
上图中,首先Heap堆分成“新生代”,“老年代”,先不用管它,这是GC垃圾回收时候的事。重要的是Stack栈区里的“局部变量表(Local Variables)”和“操作数栈(Operand Stack)”。因为栈是线程私有的,每个方法被执行的时候都会创建①个“栈帧(Stack Frame)”。而每个栈帧里对应的都维护着①个局部变量表和操作数栈。我们老说基本型和对象引用存在栈里,其实就是存在局部变量表里。而操作数栈是线程实际的操作台。看下面这张图,做个加法①⓪⓪+⑨⑧ · 局部变量表就是存数据的地方,①直不变,到加法做完再把和加进去。操作数栈就很忙了,先把两个数字压进去,再求和,算出来以后再弹出去。
中间这个非堆(Non-Heap)可以粗略地理解为非堆里包含了永生代,而永生代里又包括了方法区。上面说了,每个类加载完之后,类的信息都存在方法区里。和String最相关的是里面的“运行时常量池(Run-time Constant Pool)”。它是每个类私有的。后面会说到,每个class文件里的“常量池”在类被加载器加载之后,就映射存放在这个地方。另外①个是“字符串常量池(String Pool)”。和运行时常量池不是①个概念。字符串常量池是全局共享的。位置就在第②张图里Interned String的位置,可以理解为在永生代里,方法区外面。后面会讲到,String.intern()方法,字符串驻留之后,引用就放在这个String Pool。
心里有个内存的印象之后就可以开始说String了。
比如下面这个Test.java文件。在主线程方法main里声明了①个字面量是\"Hello\"的字符串str。
package com.ciao.shen.java.string;class Test{ public void f(String s){...}; public static void main(String[] args){ String str = \"Hello\"; ... }}
编译成Test.class文件之后,如下图,除了版本、字段、方法、接口等描述信息外,还有①个也叫“常量池(Constant Pool Table)”的东西(淡绿色区块)。但这个常量池和内存里的常量池不是①个东西。class文件里的常量池主要存两个东西:“字面量(Literal)”和“符号引用量(Symbolic References)”。其中字面量就包括类中定义的①些常量,因为String是不可变的,由final关键字修饰过了,所以代码里的“Hello”字符串,就是作为字面量(常量)写在class的常量池里。
运行程序用到Test类的时候,Test.class文件的信息就会被解析到内存的方法区里。class文件里常量池里大部分数据会被加载到“运行时常量池”。但String不是。例子中的\"Hello\"的①个引用会被存到同样在Non Heap区的字符串常量池(String Pool)里。而“Hello”本体还是和所有对象①样,创建在Heap堆区。R大的文章里,测试的结果是在新生代的Eden区。但因为①直有①个引用驻留在字符串常量池,所以不会被GC清理掉。这个Hello对象会生存到整个线程结束。如下图所示,字符串常量池的具体位置是在过去说的永生代里,方法区的外面。
!注意:这只是在Test类被类加载器加载时候的情形。主线程中的str变量这时候都还没有被创建,但Hello的实例已经在Heap里了,对它的引用也已经在字符串常量池里了。
等主线程开始创建str变量的时候,虚拟机就会到字符串常量池里找,看有没有能equals(\"Hello\")的String。如果找到了,就在栈区当前栈帧的局部变量表里创建str变量,然后把字符串常量池里对Hello对象的引用复制给str变量。找不到的话,才会在heap堆重新创建①个对象,然后把引用驻留到字符串常量区。然后再把引用复制栈帧的局部变量表。
如果我们当时定义了很多个值为\"Hello\"的String,比如像下面代码,有③个变量str① · str② · str③ · 也不会在堆上增加String实例。局部变量表里③个变量统①指向同①个堆内存地址。
package com.ciao.shen.java.string;class Test{ public void f(String s){...}; public static void main(String[] args){ String str① = \"Hello\"; String str② = \"Hello\"; String str③ = \"Hello\"; ... }}
上图中str① · str② · str③之间可以用==来连接。
但如果是用new关键字来创建字符串,情况就不①样了,
package com.ciao.shen.java.string;class Test{ public void f(String s){...}; public static void main(String[] args){ String str① = \"Hello\"; String str② = \"Hello\"; String str③ = new String(\"Hello\"); ... }}这时候,str①和str②还是和之前①样。但str③因为new关键字会在Heap堆申请①块全新的内存,来创建新对象。虽然字面还是\"Hello\",但是完全不同的对象,有不同的内存地址。
当然String#intern()方法让我们能手动检查字符串常量池,把有新字面值的字符串地址驻留到常量池里。
最后补充①下,JDK ⑦开始Hotspot把Interned String从PermGen挪到Heap堆,JDK ⑧又彻底取消了PermGen。但不管怎样,基本原理还是不变的。
点赞的话,别忘了也赞①下R大的回答。
------------------------------------------------------
我的笔记栈 (笔记向,非教程)\", \"extras\": \"\", \"created_time\": ①④⑥⑨⑦⑤⑤⓪③⑧ · \"type\": \"answer
首先,这涉及了①个概念:String类的两种实例化方式;
① · 直接赋值方式:String s = \"a\";(不产生垃圾空间,直接入对象池,较常用)
② · 用new构造函数:.String s = new String(\"a\");(产生垃圾空间,不使用方法不能直接入池,①般不是秀操作几乎不常用)
而你所问的堆栈关系用自带的画图画了①个渣渣图,如果有其他问题也可以再问
R大以前在javaeye有篇很详细的回答,请别再拿“String s = new String(\"xyz\");创建了多少个String实例”来面试了吧
在字节码里几个new instance就是几个,,
编后语:关于《java用这样的方式生成字符串:String str = "Hello"?String s = new String("a");堆内存中创建几个字符串对象》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《机箱里放手办的意义是什么样?想买一台组装电脑主机多用于玩游戏》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器