新建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
引自 http://blog.csdn.net/jadyer/article/details/5961747
分享到:
相关推荐
### Java String对象的经典问题 #### 一、String 类与对象机制概述 在Java中,`String`类是一个非常重要的类,它提供了丰富的功能用于处理文本数据。`String`类是不可变的(immutable),这意味着一旦一个`String`...
解析Java中的String对象的数据类型字符串 Java中的String对象是一种特殊的数据类型,它不同于基本数据类型,也不同于其他对象。String对象的默认值是null,但它又是一种特殊的对象,有其它对象没有的一些特性。 ...
### 创建string对象过程的内存分配详解 #### 一、引言 在Java中,`String` 类是最常用的数据类型之一,用于表示不可变的字符序列。`String` 对象的创建涉及复杂的内存分配机制,特别是在Java虚拟机 (JVM) 的环境中...
在 JAVA 中,存在一个字符串池(String Pool),用于保存和共享 String 对象。String 对象池可以提高效率,因为它可以避免创建重复的 String 对象。 String 对象池是由 String 类维护的,可以通过 intern() 方法来...
`String Pool`是存储`String`字面量的缓存池,当通过字面量的方式创建`String`对象时,Java虚拟机首先检查`String Pool`中是否已经存在相同的字符串,如果存在,则返回该字符串的引用,而不是创建一个新的对象。...
#### 一、String 类与常量池、字符串池的基本概念 在 Java 中,`String` 类并不属于八种基本数据类型之一,而是作为一个对象存在。这意味着 `String` 对象默认值为 `null`。尽管如此,`String` 类拥有其独特之处,...
Java中的字符串对象`String`是编程中非常常见且重要的元素,它们在内存管理上有一些特殊之处,这在理解和优化程序性能时尤其关键。本篇文章将深入探讨`String`对象的内存分析,包括栈、堆、常量池以及静态存储的概念...
- 直接通过字面量创建的`String`对象,如`"a"`,会存储在字符串池(String Pool)中。如果池中已有相同的字符串,就不会再创建新的对象,而是重用已存在的。 - 使用`new`关键字创建的`String`对象则会在堆内存中...
当创建一个新的 String 对象时,Java 会首先在 String.Pool 中查找是否已经存在该字符串,如果存在则返回该字符串的引用,否则创建一个新的字符串对象。 五、String 对象的应用 String 对象是 Java 中最基本的数据...
Java中String对象具有不可变性(immutable)的特点,这意味着一旦创建了一个String对象,其内容就不能被更改。这种特性虽然确保了字符串的安全性和线程安全性,但也可能在某些情况下导致额外的内存消耗。因此,理解...
假定我现在有一个任务,就是对一堆字符串进行格式化,为了加快速度,采用了多线程的方式允许,而格式化则是通过对象StringFormat来实现。 采用池技术,目的在于循环利用此对象,避免不停的生成和回收类。 也许本...
2. **缓存效率**:当创建相同的字符串时,如果该字符串已经存在于字符串池(String Pool)中,则不会创建新的实例,而是返回已存在的引用。这避免了内存中存在多个相同字符串副本的情况,提高了空间效率。 3. **性能...
String对象不可变,无法修改 ``` 这段代码是错误的,因为 `String` 对象的字符内容是不可变的,不能通过 `charAt` 或其他方法直接修改其内容。 ##### (3) 举例3 利用 `StringBuilder` 或 `StringBuffer` 修改字符...
本文将基于提供的代码片段深入探讨与 `String` 类型相关的几个关键概念,包括字符串常量池、字符串比较、以及 `new` 关键字在创建 `String` 对象时的影响。 #### 一、字符串常量池的理解 首先,我们需要理解字符串...
使用这种方式创建的字符串会被存储在一个特殊的内存区域——字符串常量池(String Literal Pool)中。如果再次尝试创建相同的字符串字面量,Java会直接引用已存在的字符串对象,而不是创建新的实例。 2. **new...
public class StringPool { private static class StringWrapper implements Poolable<String> { private String value; public StringWrapper(String value) { this.value = value; } @Override public ...
《Apache Commons Pool 1.5.5:Java对象池化框架详解》 Apache Commons Pool 是一个广泛使用的开源项目,提供了一种高效的对象池化服务。本篇将详细讲解Apache Commons Pool 1.5.5版本的核心特性、工作原理以及如何...
String对象存在于Java的字符串常量池(String Pool)中,这个池是为了优化性能,避免多次创建相同的字符串对象。当创建一个新的String实例时,如果常量池中已经存在相同内容的字符串,那么就会返回池中已有的对象...