String str=new String("abc"); 紧接着这段代码之后的往往是这个问题,那就是这行代码究竟创建了几个String对象呢?
相信大家对这道题并不陌生,答案也是众所周知的,2个。
接下来我们就从这道题展开,一起回顾一下与创建String对象相关的一些JAVA知识。
我们可以把上面这行代码分成String str、=、"abc"和new String()四部分来看待。String str只是定义了一个名为str的String类型的变量,因此它并没有创建对象;=是对变量str进行初始化,将某个对象的引用(或者叫句柄)赋值给它,显然也没有创建对象;现在只剩下new String("abc")了。那么,new String("abc")为什么又能被看成"abc"和new String()呢?
我们来看一下被我们调用了的String的构造器:
public String(String original) { //other code ... } 大家都知道,我们常用的创建一个类的实例(对象)的方法有以下两种:
一、使用new创建对象。
二、调用Class类的newInstance方法,利用反射机制创建对象。
我们正是使用new调用了String类的上面那个构造器方法创建了一个对象,并将它的引用赋值给了str变量。同时我们注意到,被调用的构造器方法接受的参数也是一个String对象,这个对象正是"abc"。由此我们又要引入另外一种创建String对象的方式的讨论——引号内包含文本。
这种方式是String特有的,并且它与new的方式存在很大区别。
String str="abc";
毫无疑问,这行代码创建了一个String对象。
String a="abc"; String b="abc"; 那这里呢?
答案还是一个。
String a="ab"+"cd"; 再看看这里呢?
答案是三个。说到这里,我们就需要引入对字符串池相关知识的回顾了。
在JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。由于String类是final的,它的值一经创建就不可改变,因此我们不用担心String对象共享而带来程序的混乱。字符串池由String类维护,我们可以调用intern()方法来访问字符串池。
我们再回头看看String a="abc";,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。因此,我们不难理解前面三个例子中头两个例子为什么是这个答案了。
只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,对此我们不再赘述。因此我们提倡大家用引号包含文本的方式来创建String对象以提高效率,实际上这也是我们在编程中常采用的。
栈(stack):主要保存基本类型(或者叫内置类型)(char、byte、short、int、long、float、double、boolean)和对象的引用,数据可以共享,速度仅次于寄存器(register),快于堆。
堆(heap):用于存储对象
相关推荐
实际上创建了两个 String 对象,一个是”abc”对象,存储在常量空间中,一个是使用 new 关键字为对象 s 申请的空间。 二、字符串的常见操作 字符串的常见操作包括 charAt 方法、compareTo 方法、concat 方法等。 ...
第一种形式用 new() 来创建对象的,它会存放在堆中,每调用一次就会创建一个新的对象。第二种形式是先在栈中创建一个对 String 类的对象引用变量 str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,...
在这种情况下,`a` 和 `b` 都被初始化为 `"abc"`,但它们并没有通过 `new` 关键字创建新的 `String` 对象。因此,根据Java的字符串池优化机制,这两个字符串实际上共享了内存中的同一个实例,所以 `a == b` 返回 `...
` 这种方式显式地使用了`new`关键字来创建对象。 2. **内存分配差异**:简化语法实际上利用了Java的字符串常量池机制,使得相同的字符串仅被创建一次并存储于常量池中,从而节省了内存资源。相比之下,使用`new ...
在 JAVA 中,可以使用“==”运算符来比较两个 String 对象是否相等。如果比较的是两个基本类型,则是判断它们的值是否相等;如果比较的是两个对象变量,则是判断它们的引用是否指向同一个对象。 例如,Java 代码: ...
在 JavaScript 中,很多开发者都遇到过一个问题:为什么 `a = "abc"` 不等于 `a = new String("abc")`?这是因为在 JavaScript 中,存在两种类型的字符串:原始类型(primitive type)和包装类型(wrapper type)。 ...
- **"=="运算符**:主要用于比较两个对象的引用是否相同,即它们是否指向内存中的同一个位置。对于基本数据类型,"=="比较的是值;而对于引用数据类型,如String,"=="比较的是对象的引用地址。 示例: ```java ...
- `i1`和`i2`的值为256,超过了127,每次装箱都会创建新对象,所以`i1==i2`为`false`,创建了两个对象。 理解这些内存分配规则对于编写高效、内存友好的Java代码至关重要。在处理大量字符串操作时,避免不必要的`...
因此,即使两个通过`new String()`创建的`String`对象具有相同的值,它们也会有不同的对象引用。 #### 三、String 比较 Java中有两种主要的方式来比较`String`对象: 1. **使用“==”运算符**:这种方法比较的是...
Java 中的 String 类是一个特殊的类,它是一个 immutable 类,也就是说,一旦创建了 String 对象,它的值就不能被改变。String 类的 immutable 性质是通过 final 关键字实现的。 二、String 对象的创建 Java 中有...
3. 当比较两个由 `new String()` 创建的对象时,即使它们的内容相同,使用 `==` 运算符比较的结果也是 `false`,因为它们指向不同的内存地址。正确的方式应该是使用 `equals()` 方法进行比较。 示例代码如下: ```...
这意味着即使两个使用new关键字创建的字符串内容完全相同,它们也是不同的对象,拥有不同的内存地址。 ### 二、两种实例化方式的区别 1. **内存位置**:字面量方式创建的字符串存储在方法区的字符串常量池中,而...
6. `replace(oldChar, newChar)`或`replace(oldString, newString)`:替换字符串中符合条件的字符或子串。 比较`String`对象: - `equals(anotherString)`:比较两个字符串的内容是否相等,不考虑大小写。 - `...
这主要是出于两个原因考虑:一是为了确保字符串对象的不可变性,从而可以在整个系统中安全地共享这些对象;二是为了优化性能,由于字符串常被用作键(如在哈希表中),不可变性使得这些键更加可靠。 ### 2. String ...
即使两个对象包含相同的字符序列,它们也是不同的对象。 #### 三、字符串比较 字符串比较是常见的操作之一,主要包括以下几种方法: 1. **使用`==`操作符**:检查两个字符串变量是否指向同一个对象。 ```java ...
对于 `String` 类型来说,如果两个字符串都是通过直接赋值的方式创建的,并且它们的内容相同,则 `==` 比较的结果为 `true`。 - **`.equals()`**:用于比较两个字符串的内容是否相同,而不关心它们是否是同一个对象...
- **示例**:通过 `new` 关键字创建的对象,例如 `new String("abc")`,会在堆中分配内存。 #### 二、String 创建方式的分析 对于字符串来说,其创建的方式有两种主要形式: 1. **直接赋值**: - 如 `String ...
这一语句创建了两个对象:一个是常量池中的 "abc",另一个是堆中的 String 对象。 6. String、StringBuffer、StringBuilder 有什么区别? 答案:String、StringBuffer、StringBuilder 最大的不同是 String 不可变...