新建String对象到底生成几个对象呢?下面将对其进行详细介绍
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
总结一下:
1、通过new关键字创建的对象是在堆上,与字符串常量池内存地址肯定不一样. 2、通过new String("sb"),如果在常量池中没有sb,则会新建这个sb对象放进去,然后再到堆中创建一个sb对象。这样就会有两个值均为sb的对象了。 3、通过直接赋值String s = 'sb',则会直接在常量池寻找是否存在这个sb,不存在则在常量池中创建,存在则直接返回这个sb在常量池中的内存地址,使引用变量s指向它。 4、String.intern()方法:'sb'.intern(),则会去常量池查询是否存在sb这个字符串对象,存在则直接返回内存地址,不存在则创建再返回内存地址,反正最后常量池中肯定会有这个sb字符串对象,而返回的结果也一定是常量池中的内存地址。
相关推荐
字符串池(String Pool)是.NET内存管理的一个重要概念,它优化了字符串对象的创建和存储,以提高性能。在此WinForm字符串池源码中,我们可以深入理解这个概念的实现细节。 字符串池的主要目的是减少内存中的重复...
如果在常量池中已经存在相同的Unicode字符串常量,那么String.intern()方法将返回该常量池中的字符串常量的引用,否则,它将在常量池中增加一个新的字符串常量。 例如,String s0="kvill";,String s1=new String(...
在Java编程语言中,字符串常量池(String Constant Pool)是一个重要的概念,它与程序的内存管理和性能优化密切相关。理解这个概念对于任何Java开发者来说都至关重要。字符串常量池是Java虚拟机(JVM)在运行时为...
1. **字符串池(String Pool)** Java中的字符串是不可变对象,为了提高性能和内存利用率,引入了字符串池。当创建一个字符串时,Java会检查池中是否存在相同内容的字符串,如果存在则直接引用,否则新建并添加到池中...
C#字符串内存分配与驻留池是.NET框架中一种高效的内存管理策略,主要涉及到字符串对象在内存中的存储和复用。在C#中,字符串(String)是一个不可变的类型,这意味着一旦创建,其内容就不能改变。这种特性使得字符串...
`,该字符串会被存储在一个特殊的区域——字符串常量池(String Constant Pool)中。如果尝试再次创建一个相同内容的字符串,如`String s2 = "Hello";`,实际上s2指向的是字符串池中已存在的"Hello"。这种方式可以...
使用这种方式创建的字符串会被存储在一个特殊的内存区域——字符串常量池(String Literal Pool)中。如果再次尝试创建相同的字符串字面量,Java会直接引用已存在的字符串对象,而不是创建新的实例。 2. **new...
传统的内存管理优化方案主要关注字符串的使用效率,例如消除常量重复(String Pool)和延迟分配等技术。然而,这些方法无法直接处理已经存在于堆中的无用字符串数据,只能依赖于垃圾收集器的定时清理。而垃圾收集器...
SQL Server 连接字符串详解 SQL Server 连接字符串是数据库连接的一个标准方面,在应用程序开发中扮演着至关重要的角色。连接字符串是数据库连接的关键,它指定了数据库服务器、数据库、用户名、密码等必要信息。...
`String Pool`是存储`String`字面量的缓存池,当通过字面量的方式创建`String`对象时,Java虚拟机首先检查`String Pool`中是否已经存在相同的字符串,如果存在,则返回该字符串的引用,而不是创建一个新的对象。...
- 使用`String.intern()`方法可以将字符串放入字符串常量池,如果池中已存在相同值,则返回池中的引用。 9. **Java 11的新特性**: - `strip()`, `stripLeading()`, 和 `stripTrailing()`方法用于去除字符串两侧...
#### 一、String 类与常量池、字符串池的基本概念 在 Java 中,`String` 类并不属于八种基本数据类型之一,而是作为一个对象存在。这意味着 `String` 对象默认值为 `null`。尽管如此,`String` 类拥有其独特之处,...
本文将基于提供的代码片段深入探讨与 `String` 类型相关的几个关键概念,包括字符串常量池、字符串比较、以及 `new` 关键字在创建 `String` 对象时的影响。 #### 一、字符串常量池的理解 首先,我们需要理解字符串...
- **直接赋值**:这种方式会在**字符串常量池**(String Pool)中查找或创建一个对应的`String`对象,并将变量指向该对象。字符串常量池是Java堆的一部分,专门用来存储字符串字面量。如果字符串常量池中已经存在...
`intern()`方法是一个非常特殊的函数,它将字符串常量池(String Constant Pool)的概念引入到我们的讨论中。 字符串常量池是Java虚拟机(JVM)内存模型的一部分,位于堆内存的常量池区域。在Java 6及之前,这个池...
在 Java 中,字符串池(String Intern Pool)是通过使用唯一的共享 String 对象来使用相同的值不同的地址表示字符串的过程。字符串池可以使用自己定义的 Map<String, String> 或者使用 JDK 提供的 String.intern() ...
字面量(Literal)与字符串常量池(String Constant Pool) 字符串字面量指的是直接用双引号括起来的字符串,例如 `"abc"`、`"HelloWorld"` 等。当创建这样的字符串时,JVM会检查字符串常量池中是否已经存在相同的...
2. **缓存效率**:当创建相同的字符串时,如果该字符串已经存在于字符串池(String Pool)中,则不会创建新的实例,而是返回已存在的引用。这避免了内存中存在多个相同字符串副本的情况,提高了空间效率。 3. **性能...