字符内存转成字符串_字符串内存内部

字符内存转成字符串

本文基于我对StackOverflow的回答 。 我正在尝试解释String类如何存储文本,内部存储和常量池如何工作。

这里要理解的要点是String Java对象与其内容– private value字段下的char[]之间的区别。 String基本上是char[]数组的包装器,将其封装并使其无法修改,因此String可以保持不变。 另外, String类还记住该数组的实际部分(请参阅下文)。 这一切都意味着您可以有两个不同的String对象(相当轻量)指向相同的char[]

我会告诉你一些例子,连同hashCode()的每个StringhashCode()内部的char[] value字段(我将其称之为文本字符串从区分)。 最后,我将显示javap -c -verbose输出以及测试类的常量池。 请不要将类常量池与字符串文字池混淆。 它们并不完全相同。 另请参见了解javap的常量池输出 。

先决条件

为了进行测试,我创建了一个实用程序方法来破坏String封装:

private int showInternalCharArrayHashCode(String s) {final Field value = String.class.getDeclaredField("value");value.setAccessible(true);return value.get(s).hashCode();
}

它将打印char[] value hashCode() ,有效地帮助我们了解此特定String是否指向相同的char[]文本。

一个类中的两个字符串文字

让我们从最简单的示例开始。

Java代码

String one = "abc";
String two = "abc";

顺便说一句,如果您只写"ab" + "c" ,则Java编译器将在编译时执行级联,并且生成的代码将完全相同。 仅当在编译时知道所有字符串时,此方法才有效。

类常量池
每个类都有自己的常量池 -常量值列表,如果它们在源代码中多次出现,则可以重用。 它包括常见的字符串,数字,方法名称等。
这是上面示例中常量池的内容:

const #2 = String   #38;    //  abc
//...
const #38 = Asciz   abc;

要注意的重要事项是String常量对象( #2 )和字符串指向的Unicode编码文本"abc"#38 )之间的区别。

字节码
这是生成的字节码。 请注意, one引用和two引用都分配有指向"abc"字符串的相同#2常量:

ldc #2; //String abc
astore_1    //one
ldc #2; //String abc
astore_2    //two

输出量
对于每个示例,我将打印以下值:

System.out.println("one.value: " + showInternalCharArrayHashCode(one));
System.out.println("two.value: " + showInternalCharArrayHashCode(two));
System.out.println("one" + System.identityHashCode(one));
System.out.println("two" + System.identityHashCode(two));

这两对相等并不奇怪:

one.value: 23583040
two.value: 23583040
one: 8918249
two: 8918249

这意味着不仅两个对象都指向相同的char[] (下面的相同文本),所以equals()测试将通过。 但更重要的是, onetwo是完全相同的引用! 因此, one == two也是正确的。 显然,如果onetwo指向同一个对象,则one.valuetwo.value必须相等。

文字和new String()  

Java代码
现在,我们都在等待该示例–一个字符串文字和一个使用相同文字的新String 。 这将如何运作?

String one = "abc";
String two = new String("abc");

在源代码中两次使用了"abc"常量这一事实应该给您一些提示……

类常量池与上面相同。

字节码

ldc #2; //String abc
astore_1    //onenew #3; //class java/lang/String
dup
ldc #2; //String abc
invokespecial   #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V
astore_2    //two

仔细地看! 第一个对象的创建方法与上面相同,不足为奇。 它只需要从常量池中常量引用已经创建的String#2 )。 但是,第二个对象是通过常规构造函数调用创建的。 但! 第一个String作为参数传递。 可以将其反编译为:

String two = new String(one);

输出量
输出有点令人惊讶。 第二对表示对String对象的引用是可以理解的-我们创建了两个String对象-一个在常量池中为我们创建,第二个是为two手动创建的。 但是,为什么第一对建议两个String对象都指向同一个char[] value数组呢?

one.value: 41771
two.value: 41771
one: 8388097
two: 16585653

当您查看String(String)构造函数的工作原理时,这一点变得很清楚(此处已大大简化了):

public String(String original) {this.offset = original.offset;this.count = original.count;this.value = original.value;
}

看到? 当基于现有对象创建新的String对象时,它会重用 char[] valueString是不可变的,不需要复制已知永远不会修改的数据结构。 而且,由于new String(someString)创建了现有字符串的精确副本,并且字符串是不可变的,因此显然没有理由同时存在两者。
我认为这是一些误解的线索:即使您有两个String对象,它们仍可能指向相同的内容。 如您所见, String对象本身很小。

运行时修改和intern()  

Java代码
假设您最初使用了两个不同的字符串,但是在进行一些修改之后,它们都是相同的:

String one = "abc";
String two = "?abc".substring(1);  //also two = "abc"

Java编译器(至少是我的)不够聪明,无法在编译时执行此类操作,请看一下:

类常量池
突然我们以指向两个不同常量文本的两个常量字符串结尾:

const #2 = String   #44;    //  abc
const #3 = String   #45;    //  ?abc
const #44 = Asciz   abc;
const #45 = Asciz   ?abc;

字节码

ldc #2; //String abc
astore_1    //oneldc #3; //String ?abc
iconst_1
invokevirtual   #4; //Method String.substring:(I)Ljava/lang/String;
astore_2    //two

拳头弦照常构造。 通过首先加载常量"?abc"字符串,然后在其上调用substring(1)来创建第二个。

输出量

这里不足为奇–我们有两个不同的字符串,指向内存中两个不同的char[]文本:

one.value: 27379847
two.value: 7615385
one: 8388097
two: 16585653

好吧,文本并没有真正的不同equals()方法仍然会产生true 。 我们有两个不必要的相同文本副本。
现在我们应该进行两次练习。 首先,尝试运行:

two = two.intern();

在打印哈希码之前。 onetwo不仅指向同一文本,而且它们是相同的参考!

one.value: 11108810
two.value: 11108810
one: 15184449
two: 15184449

这意味着one.equals(two)one == two测试都将通过。 我们还节省了一些内存,因为"abc"文本在内存中仅出现一次(第二个副本将被垃圾回收)。
第二个练习略有不同,请查看以下内容:

String one = "abc";
String two = "abc".substring(1);

显然onetwo是两个不同的对象,指向两个不同的文本。 但是输出如何表明它们都指向同一个char[]数组?!

one.value: 11108810
two.value: 8918249
one: 23583040
two: 23583040

我将答案留给你。 它会教您substring()工作原理,这种方法的优点是什么以及何时会导致大麻烦 。

得到教训

  • String对象本身相当便宜。 它指向的文本占用了大部分内存
  • String只是char[]的薄包装,以保持不变性
  • new String("abc")作为内部文本表示被重用是不是真的那么贵。 但是还是要避免这样的构造。
  • 从编译时已知的常量值连接String时,连接由编译器而不是由JVM完成
  • substring()有点棘手,但最重要的是,就使用的内存和运行时间而言,它都很便宜(在两种情况下均保持不变)

参考: Java和社区博客中来自JCG合作伙伴 Tomasz Nurkiewicz的字符串内存内部 。


翻译自: https://www.javacodegeeks.com/2012/07/string-memory-internals.html

字符内存转成字符串

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python安装库报错Microsoft visual c++ 14.0 is required问题解决办法

下载安装包安装即可&#xff1a; https://964279924.ctfile.com/fs/1445568-239446865 or http://www.liangchan.net/liangchan/10220.html转载于:https://www.cnblogs.com/stkares/p/9384424.html

Apache PDFBox命令行工具:无需Java编码

在博客文章Apache PDFBox 2中 &#xff0c;我演示了将Apache PDFBox 2用作从Java代码中调用的库来操作PDF。 事实证明&#xff0c;Apache PDFBox 2还提供了可以直接从命令行直接使用的命令行工具 &#xff0c;而无需其他Java编码。 有几种命令行工具可用&#xff0c;我将在本文…

shocked的歌曲 类似shell_Shell Shocked歌词

Shell Shocked歌词添加日期&#xff1a;2014-11-04 时长&#xff1a;03分24秒 歌手&#xff1a;忍者神龟Kylie Minogue - Speakerphonewww.9ku.com 活在当下 制作LightsMindEyesHeartsLights (Flashin) Sound (Crashin)Minds (Blowin) Body (Rockin)Eyes (Lockin) Lips (Touchi…

除法上取整、下取整

C &#xff1d; A / B&#xff1b;// 默认就是下取整 C &#xff1d; (AB-1)/B; // 上取整算法

intellij idea

使用intellij idea的经验、会慢慢补全 目录 转载于:https://www.cnblogs.com/black-/p/9391846.html

ACM中Java使用总结

Java在ACM中的主要应用是大数类【个人见解】。做个小总结&#xff0c;留作模板用。 类名默认为Main。 输入&#xff1a; 声明一个输入对象cin;Scanner cinnew Scanner(System.in); 输入一个int值&#xff1a;Int acin.nextInt(); 输入一个大数&#xff1a;BigDecimal acin.next…

在分析了47,251个依赖关系之后,2016年排名前100的Java库

谁在上面&#xff0c;谁在后面&#xff1f; 我们分析了Github上的47,251个依赖关系&#xff0c;并抽取了前100个Java库 长周末我们最喜欢的消遣是浏览Github并搜索流行的Java库。 我们决定与您分享乐趣和信息。 我们分析了Github上前3,862个Java项目使用的12,059个独特Java库…

tensorflow源码编译教程_源码编译安装tensorflow 1.8

参考官方指南基本要求官网测试过的源代码配置如下&#xff1a;image也就是说&#xff0c;按照这个版本安装的话不应该再产生版本的问题了。我的配置ubuntu 16python 2.7nccl 2.3gcc 4.8.5cuda 7.1.4cudnn 9.0 (具体是9.0.176但是在./configure的那里不用输这么仔细&#xff0c;…

html2canvas关于图片不能正常截取

问题 首先说说遇到了什么问题。首先有这么一个需求。需要前端根据后端传过来数据&#xff0c;动态的生成图片。图片中的文案、背景图片、用户头像全部都是通过后端的接口获取。但是使用 html2canvas 生成的canvas有些图片成功的在canvas里生成了。但是有些图片无论如何都显示不…

tortoise清理本地分支_本地:延庆运污水环卫抽化粪池

北京兴百荣清洁公司是清理排水管道的技术服务中心。提供下水道疏通&#xff0c;化粪池清理&#xff0c;抽污水&#xff0c;化粪池清掏&#xff0c;管道清淤&#xff0c;下水道清洗&#xff0c;化粪池清理&#xff0c;抽粪&#xff0c;管道疏通&#xff0c;雨水管道清理&#xf…

C++矩阵优化算法

写在前面的话&#xff1a;此矩阵优化算法并非原创&#xff0c;笔者只是转述了一种智慧。 在C中&#xff0c;定义一个矩阵通常是这样的: class MyMatrix { ........ public: ........ float data[50000]; } 这里为了方便说明问题&#xff0c;使用固定大小的数…

win7(windows 7)系统下安装SQL2005(SQL Server 2005)图文教程

由于工作需要&#xff0c;今天要在电脑上安装SQL Server 2005。以往的项目都是使用Oracle&#xff0c;MS的数据库还真的没怎么用过&#xff0c;安装Oracle已经轻车熟路&#xff0c;但装SQL Server好像还有点小麻烦&#xff0c;所以记录下来&#xff0c;以留备用。 ------------…

tensorflow中的Supervisor

tf.train.Supervisor()可以帮我们简化一些事情&#xff0c;可以保存模型参数和Summary&#xff0c;它有以下的作用&#xff1a; 1&#xff09;自动去checkpoint加载数据或初始化数据 &#xff0c;因此我们就不需要手动初始化或者从checkpoint中加载数据 2&#xff09;自身有一个…

jaxb 解析list元素_JAXB和根元素

jaxb 解析list元素XmlRootElement是人们习惯于与JAXB&#xff08;JSR-222&#xff09;一起使用的注释。 目的是将根元素与类唯一关联。 由于JAXB类映射到复杂类型&#xff0c;因此一个类有可能对应于多个根元素。 在这种情况下&#xff0c;无法使用XmlRootElement &#xff0c;…

抓娃娃机爪不动怎么办_黄子韬吃娃娃菜能把临时牙咬断?种植牙到底结实不结实?...

黄子韬的临时牙上热搜了&#xff0c;最高排名热搜榜第四位。有关牙齿的事儿瞬间让我这个口腔医生来了八卦之心&#xff0c;在看了后面的各种评论之后&#xff0c;我大概梳理清楚这到底是怎么回事了&#xff1a;小时候因为调皮所以摔断了门牙&#xff0c;前些日子门牙做了种植牙…

从SVN迁移到Git(包括SVN历史纪录)【最系统的讲解】

从SVN迁移到git有很多方法&#xff0c;最简单的就是使用git包自带的git svn命令&#xff08;git v1.7及以上&#xff09;。除此之外还有一些第三方的专门的转换工具如http://www.subgit.com/&#xff0c;https://www.atlassian.com/git/tutorials/migrating-overview/等。但是由…

反射的应用

class Teacher:OPERATE_DIC [(创建课程, create_course),(创造学生, create_student),(创建课程, create_course),(查看学生信息, check_student_info),]def __init__(self, name):self.name namedef create_course(self):print(创建课程)def create_student(self):print(创建…

抖音数据统计_26万条抖音数据背后的推荐逻辑以及严重失调的男女比例

本文作者&#xff1a;喜哥&#xff08;张佳&#xff09;易灵微课《数据分析-认知与实践》讲师新榜数据分析师人人都是产品经理、华尔街见闻专栏作家简书科技类优秀作者本文首发自公众号喜新&#xff08;noyanjiu&#xff09;,如需转载请注明出处这次是26W条数据&#xff0c;应该…

SQL SERVER 数据库主键和外键的思考

SQL SERVER 数据库主键和外键的思考 什么是主键&#xff1a; 主键是指表中一个列或者列的组合&#xff0c;其值能够唯一的标识表中的每一个行。这样的一列或者多列成为表的主键&#xff0c;通过它可以强制表的实体完整性。当创建或者更改表时可以通过定义PRIMARY KEY约束来创建…

在Gradle 2.13中更好地处理“在插件Y上找不到属性X”

您可能从未听说过的服务缺少用户名&#xff0c;密码或令牌&#xff1f; 这通常发生在您尝试执行任何操作&#xff08;例如仅构建项目&#xff09;时&#xff0c;不仅发生在使用给定的插件&#xff08;例如在线代码覆盖工具&#xff09;时。 我不想修改我的环境&#xff0c;而只…