学习String相关知识点的一些总结

国际新闻 浏览(1500)

今天的猪脚来自一个例子。

执行结果:

False

False

False

False

False

False

让我们看看下面的结果

首先,我们都知道这两个比较是如何相等的。如果==比较两种基本类型,则根据值是否相等来判断真假,如果不相等,则判断存储器的地址是否相同。

解释变量strings3="a" "b "指向的地址不等于stringss=" ab

.但是,s3并不直接指向常量池中的“ab”地址,因此“a”和“b”的过程与新对象的过程相似。指向它在堆中的地址。

以下指令都指向同一个地址,都指向常量池中的“ab”。

这可以结合以下常见问题来解释:

众所周知,字符串有两种声明。

这两个声明是不同的。首先,堆栈内存A指向常量池中的“abc”。

第二种方法是通过在堆中创建内存来创建一个字符串对象,然后这个对象指向线程池中的“abc”。

换句话说,这是下面问题的答案。

字符串a=新字符串(“abc”)创建了多少个对象?

找出常量池中是否有“abc”对象。

如果有,返回相应的引用实例。

如果没有,创建相应的实例对象。

在堆中新建一个字符串(“abc”)对象

将对象地址分配给str4并创建一个引用。

因此,如果常量池中没有“abc”文字,则创建两个对象,否则,创建一个对象并创建一个引用变量,并经常问这样一个不同的问题:

STRSTRSTR1=新字符串(“A”“B”);将创建多少个对象?

字符串str2=新字符串(“ABC”)“ABC”;将创建多少个对象?

str 1:

字符串常量池:“ab”:1

heap:newstring(“ab”):1

Reference:str 1:1

Total:5

str 2:

字符串常量池:“ABC”:1

heap:newstring(“ABC”):1

Reference:STR 2:1

Total:3

以下图形显示了字符串a=新字符串(“ABC”)在jvm内存中的分布。

JVM内存区

JVM内存区分为5个部分:程序计数器、虚拟机堆栈、本地方法区、堆和方法区。

根据线程是否是私有的,这5个部分可以分为两类。

thread private:程序计数器,虚拟机堆栈,本地方法区域。

线程共享:堆,方法区。

program counter (thread private):这种类型的内存也称为“thread private”内存。

如果java方法正在执行,计数器记录虚拟机字节码指令的地址(当前指令的地址)。

虚拟机堆栈(线程私有):每个方法在执行时创建一个堆栈框架。从调用到执行的每个方法都对应于虚拟机堆栈中堆栈之间的堆栈帧。

stack Frame是用于存储数据和部分处理结果的数据结构,也用于处理动态链接、方法返回值和调度异常。堆栈帧是用方法调用创建的,并随着方法的结束而被销毁无论方法正常完成还是异常完成(抛出一个未在方法中捕获的异常),都被视为方法的结束。

本地方法区(线程私有):如果虚拟机实现使用C链接模型来支持本机调用,那么堆栈将是一个C堆栈,但是HotSpot虚拟机直接将本地方法堆栈与虚拟机堆栈相结合。

堆-线程共享-运行时数据区:由于现代虚拟机采用了代收集算法,从垃圾收集的角度来看,Java堆可以进一步分为:新生代(伊甸园、从幸存者到幸存者)和老年。

。Java虚拟机对类文件的每个部分(自然包括常量池)的格式都有严格的规定。用于存储任何类型数据的每个字节都必须满足规范的要求,然后才能被虚拟机批准、加载和执行。

常量池的设计保证了字符串类型的唯一性,避免了重复释放空间,节省了内存。这里可以扩展的一个问题是为什么字符串被设计成不可变的。

此外,java8还没有被元空间所取代。

Java 8:从置换到元空间)

字符串类型为什么不变量

为什么字符串被设计成不变的?

String是Java中最常用的类,并且是不可变的。字符串是如何实现不可变的,为什么字符串必须被设计成不可变的?

首先看看字符串的底层实现:

字符串的底层实现依赖于字符值[]数组。因为它依赖于基本类型变量,所以它必须是变量。字符串不可变的原因是,通过技术实现,Java开发人员将用户与字符串底层数据的操作隔离开来。

String不可变技术实现

String类由关键字final修改,这表示该类不能继承

char值[]属性,而由final修改。它表示值引用在创建后不能更改。

以上两点不能完全实现字符串不可变。原因是:

value被final修改,这只能保证引用不会被更改。然而,堆中由值指向的数组才是真正的数据。只要堆中的数组可以操作,数据仍然可以更改。

所有成员属性都由私有关键字修改。

为了实现字符串的不变性,关键是Java开发人员在设计和开发字符串的过程中没有暴露任何内部成员。同时,应用编程接口设计不操作值,而是返回一个新的字符串(),以确保字符串的不变性。

jdStringpi源代码:

整个字符串被设置为final以禁止继承,从而避免被其他人继承后的损坏。因此,字符串是在底部实现的不可变键,而不是最终键。

为什么字符串被设计成不可变的?

Safe

保证线程安全。在并发场景中,当多个线程同时读取和写入资源时,将引入竞争条件。由于字符串是不可变的,线程安全将得不到保证,因为它不会导致线程问题。

HashCode,当创建字符串时,HashCode也将被缓存。hashcode的计算与值相关。如果字符串是可变的,hashcode也会改变。对于像地图和集合这样的容器,它们的键值需要确保唯一性和一致性。因此,字符串的不变性使得它比其他对象更适合容器的键值。

Performance

只有当字符串不可变时,字符串常量池才有意义。字符串常量池的出现可以减少创建相同文字量的字符串,使不同的引用指向池中的相同字符串,并为运行时节省大量堆内存。如果字符串是变量,字符串常量池将失去其意义,基于常量池的String.intern()方法也将失败。每次创建一个新的字符串,都会在堆中创建一个新的空间,并且会占用更多的内存。

String Constant Pool

在《深入理解java虚拟机》书中写道:对于HotSpot虚拟机,根据官方发布的路线图信息,现在计划放弃永久生成,逐步采用本机内存来实现方法区。在JDK1.7的HotSpot中,原来存储在方法区域中的字符串常量池已经被删除。根据所查询的数据,在1.7和更高版本中,字符串常量池被移动到堆内存区域。同时,jdk1.8删除了整个永久代,代之以一个名为Metaspace的区域。

在JAVA语言中有8种基本类型和一种特殊类型String。这些类型提供了一个常量池的概念,以使它们运行得更快并节省更多的内存。常量池就像一个JAVA系统级缓存。在

java中创建字符串对象的两种方法分析。

有两种主要的使用方法:

直接使用双引号声明的字符串对象直接存储在常量池中。

如果它不是用双引号声明的String对象,可以使用String提供的内部方法。intern方法查询字符串常量池中是否存在当前字符串,如果不存在,则将当前字符串放入常量池中。

创建具有文字值的字符串时,JVM将首先在字符串池中查找“abc”的存在,如果不存在,则在字符串常量池中创建“abc”,然后将池中“abc”的引用地址返回给“abc”对象的引用s1,这样s1将指向字符串常量池中的“abc”字符串对象;如果是,则不创建任何对象,并且直接返回池中对象“abc”的地址,并将其分配给引用s2。因为s1和s2都指向同一字符串池中的“abc”对象,所以结果为真。

当用新关键字创建新的字符串对象时,JVM首先在字符串池中查找“xyz”字符串对象的存在。如果是这样,它将不会在池中创建“xyz”对象。它将直接在堆中创建一个“xyz”字符串对象,然后将堆中“xyz”对象的地址返回给引用s3,因此s3指向在堆中创建的“xyz”字符串对象。如果不是,首先在字符串池中创建一个“xyz”字符串对象,然后在堆中创建一个“xyz”字符串对象,然后将堆中这个“xyz”字符串对象的地址返回给s3引用,因此s3指向在堆中创建的这个“xyz”字符串对象。S4指向堆中创建的另一个“xyz”字符串对象。S3和s4是对不同对象的两个引用,结果当然是错误的。

Intern

String#intern方法的实现原理表明,该方法是一个本机方法,但注释非常清楚。"调用intern方法时,如果池中已经包含一个与该String对象相等的字符串(由equals(oject)方法确定),则返回池中的字符串。否则,此字符串对象被添加到池中,并返回对此字符串对象的引用。在1.8版本中,字符串常量池已经从方法区域中的运行时常量池分离到堆中,所以字符串对象或引用是否存储在堆中的字符串常量池中?

相关资料:

访谈不要再问我字符串

字符串类型为什么不变

字符串字符串字符串“实际存储位置”

字符串的内存模型,为什么字符串被设计成不变

彻底解析字符串# INTIN

JDK 1.8版java字符串常量池包含字符串对象或引用?

如果你也热衷于科技,欢迎加入进步小组:。

一起分享和提高!少用水,多烘干物品!欢迎大家!(不适用于进入团队的潜水员)