String对象与StringPool之间的是是非非

2024-03-16 19:08

本文主要是介绍String对象与StringPool之间的是是非非,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

package com.jadyer.detail; /** * String对象与StringPool之间的是是非非 * @author 玄玉 * */ public class StringPoolTest { public static void main(String[] args) { //【执行完该行代码,会在内存中生成两个对象,二者的内容都是abc】 //第一个对象在StringPool中,第二个对象在Java堆内存中 //注意:这里的s不是对象,s是对象的地址,叫做引用,它指向的是堆内存中的对象 //而StringPool是java.lang.String类所特有的,由于经常要用到String类的对象 //所以JVM内部为了能够重复使用String对象,便专门使用一片内存空间缓冲已存在的String对象 //★补充★:字符串常量池的作用域是整个虚拟机中,某种意义上讲是一个工程中 //在生成字符串对象的时候,String的执行流程如下: //它首先到StringPool中查找,是否存在内容为abc的对象 //如果此时StringPool中已经存在abc对象,那么它就不会在StringPool中创建abc对象了 //但由于该行代码是main()方法的第一行语句,所以此时StringPool中是空的,没有对象的 //于是它发现StringPool中没有内容为abc对象,接着它就会把abc对象放到StringPool中 //接下来它去执行new String("abc")构造方法 //我们知道:new关键字表示生成一个对象,这个对象是在Java的堆内存中的 //于是接下来它就在Java的堆内存中又生成一个内容为abc的对象 //这样就造成了StringPool中有一个abc对象,堆内存中也有一个abc对象 String s = new String("abc"); //【执行完该行代码,内存中不会生成新的对象】 //由于这里是通过直接给出字面值"abc",而不是new的方式为字符串赋值 //所以这种情况下,Java首先会到StringPool中查找有没有内容为abc的字符串对象存在 //若发现StringPool中没有abc对象,便在StringPool中新创建一个abc对象,再将引用指向新创建的abc对象 //如果在StringPool中存在abc对象,那么它就不会在StringPool中生成新的字符串对象了 //转而它会使用已经存在的字符串对象,并且将s1这个引用指向StringPool中的abc对象 String s1 = "abc"; //【执行完该行代码,内存中一共有三个对象】 //执行过程中,它会首先查看一下StringPool中有没有abc对象存在 //结果发现:有。。那么接着它就不会在StringPool中创建新的abc对象 //由于它是通过new String("abc")方式为字符串赋值的 //我们知道:只要Java中有new操作的话,就表示它会生成一个新的对象 //我们知道:而不管new多少次,都是生成新的对象,并且新的对象永远都在Java堆内存中 //所以执行该行代码时,它在堆内存中又会生成一个新的abc对象,并将其引用地址赋给s2 String s2 = new String("abc"); /** * 也就是说,在执行完前面的三行语句后,内存中共有三个对象 * 其中包含了StringPool中的一个对象和堆内存中的两个对象 */ //对于Java中的==来说,它所比较的永远永远都是两个对象的内存地址 //换句话说,比较等号左右两边的两个引用是不是指向同样的一个对象 //对于那8个原生数据类型,==比较的是它们的字面值是不是一样的 //对于引用类型,则判断它们引用的地址是不是一样,即判断两个引用指向的是否是同样一个对象 //这里s、s1、s2分别指向三个不同的对象,这三个对象分别在内存中不同的地方 //所以s、s1、s2中任意两个使用==比较时,由于三者的内存地址均不同,故返回值都是false System.out.println(s == s1); System.out.println(s == s2); System.out.println(s1 == s2); System.out.println("~~~~~~飘逸的分隔线01~~~~~~"); System.out.println(s.equals(s1)); System.out.println(s.equals(s2)); System.out.println(s1.equals(s2)); System.out.println("~~~~~~飘逸的分隔线02~~~~~~"); /** * ★当调用java.lang.String.intern()方法时★ * 若StringPool中已经包含一个等于此String对象的字符串,则返回StringPool中的字符串 * 否则,将此String对象添加到StringPool中,并返回StringPool中的此String对象的引用 */ //【当调用s.intern()时】它首先会先查StringPool中是否存在内容为abc的对象 //结果发现:有。。这时它就会将s.intern()的返回值指向StringPool中的abc对象 //换句话说:s.intern()返回的是StringPool中的abc对象的地址,即与s1相等的值 //所以s == s.intern()的判断就相当于拿s和s1进行==判断,结果当然会返回false //【当调用s1.intern()时】它还是会检查StringPool中是否存在内容为abc的对象 //结果发现:有。。这时它同样会将StringPool中abc对象的地址返回赋给s1.intern()的返回值 //而s1本身指向的就是StringPool中的abc对象,所以s1 == s1.intern()判断的结果即true //【基于同样道理】s.intern()和s2.intern()的返回值都是StringPool中的abc对象的地址 //所以s.intern() == s2.intern()判断的结果亦为true System.out.println(s == s.intern()); System.out.println(s1 == s1.intern()); System.out.println(s.intern() == s2.intern()); System.out.println("~~~~~~飘逸的分隔线03~~~~~~"); String hello = "hello"; String hel = "hel"; String lo = "lo"; //这种情况下,在使用加号操作时 //★如果★加号左右两边的操作数都是字面值(即常量值)的话 //那么它会将这两个字面值拼起来,并得到一个对象,然后检查StringPool中有没有该对象存在 //若StringPool中没有该对象的话,那么就把它放进去 //若StringPool中存在该对象的话,则不生成新的对象,而是直接返回StringPool中的该对象 //★如果★加号左右两边有一个操作数不是常量的话,即有一个是变量的话 //那么在将这两个操作数的值拼起来后,就不会检查StringPool而是直接在堆内存中生成新对象 //也就是说"hel" + "lo"最终会拼成"hello",并且它返回的是StringPool中hello的地址 //【所以hello == "hel" + "lo"判断的结果即为true】 //而"hel" + lo最终也会拼成"hello",但不同的是它所拼成的"hello"不是StringPool中的 //而是在Java堆内存中新生成的一个"hello"对象。既然一个在堆内存中,一个在StringPool中————————截至此处,有待商榷!! //【所以二者肯定不是同一个对象,故hello == "hel" + lo判断的结果即为false】 //【同理hello == hel + lo判断的结果亦为false】 System.out.println(hello == "hel" + "lo"); System.out.println(hello == "hel" + lo); System.out.println(hello == hel + lo); } }

控制台输出如下

false false false ~~~~~~飘逸的分隔线01~~~~~~ true true true ~~~~~~飘逸的分隔线02~~~~~~ false true true ~~~~~~飘逸的分隔线03~~~~~~ true false false

这篇关于String对象与StringPool之间的是是非非的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/816421

相关文章

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J

Java文件与Base64之间的转化方式

《Java文件与Base64之间的转化方式》这篇文章介绍了如何使用Java将文件(如图片、视频)转换为Base64编码,以及如何将Base64编码转换回文件,通过提供具体的工具类实现,作者希望帮助读者... 目录Java文件与Base64之间的转化1、文件转Base64工具类2、Base64转文件工具类3、

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

Java如何通过反射机制获取数据类对象的属性及方法

《Java如何通过反射机制获取数据类对象的属性及方法》文章介绍了如何使用Java反射机制获取类对象的所有属性及其对应的get、set方法,以及如何通过反射机制实现类对象的实例化,感兴趣的朋友跟随小编一... 目录一、通过反射机制获取类对象的所有属性以及相应的get、set方法1.遍历类对象的所有属性2.获取

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

Java将时间戳转换为Date对象的方法小结

《Java将时间戳转换为Date对象的方法小结》在Java编程中,处理日期和时间是一个常见需求,特别是在处理网络通信或者数据库操作时,本文主要为大家整理了Java中将时间戳转换为Date对象的方法... 目录1. 理解时间戳2. Date 类的构造函数3. 转换示例4. 处理可能的异常5. 考虑时区问题6.