String两种不同的赋值方式

本文探讨了 Java 中 String 类的两种赋值方式:使用 new 创建对象和直接赋值,并对比了这两种方式的区别。重点讲解了字符串常量池的作用及如何影响对象的创建。

String主要有这么两种赋值方式:

一、类似普通对象,通过new创建字符串对象。String str = new String("abc");

二、类似原型那样直接赋值。如String str = "abc";

 

这两种赋值方式有什么不同,估计很多人也多少有些了解?下面我们主要围绕几个问题展开:

1、为什么String可以不用new就可以创建对象?

2、这两种赋值方式有什么不同?

 

一、

打开了String.class,有这么一段介绍:

 

通过上面的介绍,我们可以清楚,直接赋值的话,赋值方式二,是通过编译器在起作用,当你对"abc"没有通过new创建时,他会自动默认给你调用构造函数new String(char value[]).

所以问题一也就有答案了。不显式调用String的构造函数(通过new叫显式调用),其实JDK编译器会自动给你加上。

但也并不全然,显式和隐式之间也有差别的。

 

二、

 

隐式:String   password="ok";

 

利用到了字符串缓冲池,也就是说如果缓冲池中已经存在了相同的字符串,就不会产生新的对象,而直接返回缓冲池中的字符串对象的引用。  
  如:  
  String   a   =   "ok";   // 新建了一个String对象
  String   b   =   "ok";   // 从缓冲池找
  String   c   =   new   String("ok");   // 新建一个String对象
  String   d   =   new   String("ok");   // 不从缓冲池找,新建一个
    
  System.out.println(a==b);//将输出"true";因为两个变量指向同一个对象。  
  System.out.println(c==d);//将输出"flase";因为两个变量不指向同一个对象。虽然值相同,只有用c.equals(d)才能返回true.

 

 

 用Eclipse Debug了一下,查看了b和c的组成,外部结构式一样的,但是内存地址没法查看。

 

 

由图可以看出,b和c的value是一样的,而equals方法正是比较value的每个字符得出结果的。而=是比较对象的内存地址得出的(引用的内容来自同一个地方):

下面是String的equals的源代码:

 

 

<think>好的,我现在需要回答用户关于Java中两种字符串创建方式的区别的问题,也就是使用`new`直接赋值的区别。用户已经提供了一些相关的引用内容,我需要结合这些内容来构建一个清晰、准确的回答。 首先,我需要回顾用户提供的引用内容: 1. **引用[1]引用[4]**:提到通过`new`创建字符串实例时,即使内容相同,也会生成不同的对象,地址不同,因此`==`比较结果为false。而直接赋值会利用常量池,可能复用已有对象,因此地址相同。 2. **引用[2]**:讨论了`intern()`方法,手动将字符串放入常量池,使得通过`new`创建的字符串在调用`intern()`后,可能与直接赋值的字符串引用相同。 3. **引用[3]**:比较了StringStringBufferStringBuilder的区别,其中提到字符串拼接时,直接赋值可能由编译器优化为StringBuilder操作,但这里可能更关注的是String的创建方式。 接下来,我需要组织这些信息,确保覆盖以下关键点: - **内存分配**:直接赋值使用常量池,而`new`在堆中创建新对象。 - **对象数量**:直接赋值可能不创建新对象(如果常量池存在),而`new`总是创建至少一个对象(可能两个,如果常量池不存在该字符串)。 - **性能差异**:直接赋值更高效,减少内存开销。 - **`intern()`方法的作用**:将堆中的字符串对象放入常量池,以便复用。 - **字符串比较**:`==`比较引用地址,`equals()`比较内容。 同时,我需要确保回答结构清晰,分点说明,并给出代码示例来展示不同情况下的行为差异。还需要注意用户可能有的后续问题,比如何时使用哪种方式,或者如何优化字符串处理性能。 可能需要注意的细节: - 直接赋值在类加载时可能就已经将字符串放入常量池? - `new String("abc")`中的"abc"本身会先检查常量池,如果没有则创建,因此这个字面量处理过程是怎样的? - 在Java不同版本中(比如Java 7之后,常量池的位置从方法区移到堆),是否有影响?不过用户可能不需要这么深入,除非问题涉及。 需要验证的信息: - `new String("abc")`是否会始终在堆中创建新对象,而不管常量池是否存在? - 直接赋值是否总是从常量池获取引用,如果没有则创建并放入池中? - `intern()`方法的具体行为,是否返回常量池中的引用,并将当前字符串加入池中(如果尚未存在)? 现在,我需要将这些信息整合成一个逻辑连贯的回答,确保准确引用用户提供的资料,并可能补充相关知识以全面覆盖问题。同时,要避免引入错误,比如混淆字符串池的行为或`intern()`方法的具体实现细节。 最后,生成相关问题,引导用户进一步探索,比如常量池机制、字符串不可变性、性能优化建议等。</think>### Java字符串两种创建方式的区别:new与直接赋值 在Java中,字符串的两种创建方式(`new`直接赋值)在内存分配、对象复用性能方面存在显著差异。以下是详细分析: --- #### 一、内存分配机制 1. **直接赋值(字面量方式)** ```java String s1 = "abc"; String s2 = "abc"; ``` - **常量池存储**:字符串字面量直接存储在**字符串常量池**(位于JVM方法区,Java 8后移至堆的元空间)中[^4]。 - **对象复用**:若常量池已存在相同字符串,直接返回其引用,无需新建对象。因此,`s1 == s2`返回`true`(地址相同)。 2. **new关键字创建** ```java String s3 = new String("abc"); String s4 = new String("abc"); ``` - **堆内存分配**:每次`new`都会在堆中创建一个新对象,即使内容相同[^1][^4]。 - **常量池依赖**:构造函数中的字面量`"abc"`会先检查常量池,若不存在则创建并存入池中。因此,`s3 == s4`返回`false`(地址不同)。 --- #### 二、对象数量对比 | 创建方式 | 常量池对象 | 堆对象 | 总对象数 | |-------------------|------------|--------|----------| | `String s = "abc"`| 0或1 | 0 | ≤1 | | `new String("abc")`| 1(若池中无) | 1 | 1或2 | **示例分析**: - 若首次执行`new String("abc")`: 1. 检查常量池,若无`"abc"`,先在池中创建该字符串(1对象)。 2. 在堆中创建新`String`对象(第2对象)。 - 直接赋值`String s = "abc"`:仅使用常量池中的对象(0新对象)。 --- #### 三、性能与内存效率 - **直接赋值优势**: - **内存节省**:避免重复对象的创建,减少堆内存占用。 - **速度更快**:省去堆内存分配对象初始化开销。 - **new的适用场景**: - 需要显式创建独立对象(如避免常量池污染)。 - 动态构建字符串(如`new String(charArray)`)。 --- #### 四、字符串比较行为 1. **`==`操作符** - 直接赋值:比较常量池地址,相同内容返回`true`。 - `new`创建:比较堆对象地址,始终返回`false`(即使内容相同)。 ```java System.out.println(s1 == s2); // true(直接赋值) System.out.println(s3 == s4); // false(new创建) ``` 2. **`equals()`方法** 无论创建方式,均比较字符串内容: ```java System.out.println(s1.equals(s3)); // true ``` --- #### 五、`intern()`方法的作用 通过调用`intern()`,可将`new`创建的字符串强制放入常量池并复用引用[^2]: ```java String s5 = new String("abc").intern(); String s6 = "abc"; System.out.println(s5 == s6); // true ``` - **行为逻辑**: 1. `s5`调用`intern()`时,若常量池无`"abc"`,将堆中对象的引用存入池中; 2. 若池中已有,直接返回池中引用。 3. `s6`直接使用池中引用,因此`==`结果为`true`。 --- ### 总结对比表 | 特性 | 直接赋值 | new创建 | |---------------------|--------------------------|--------------------------| | 内存区域 | 常量池 | 堆内存 | | 对象复用 | 是 | 否 | | 对象数(首次) | 0或1 | 1或2 | | 比较(==) | 内容相同则true | 始终false | | 性能 | 高 | 低 | | 适用场景 | 静态字符串、高频复用 | 需要独立对象或动态构建 | --- ### 相关问题 1. 如何通过`intern()`方法优化字符串内存使用? 2. 字符串常量池在不同Java版本中有哪些变化? 3. 为什么字符串设计为不可变(Immutable)? 4. 如何避免因大量`new String()`导致的内存泄漏?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值