用new创建对象和用字符串常量创建对象的区别

本文深入探讨了Java中字符串的不同创建方式及其在内存中的表现形式,包括堆、栈和字符串常量池之间的交互,并通过示例代码展示了字符串拼接时的行为差异。

1、Demo1:

public class StringDemo2 {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = "hello";
        System.out.println(s1 == s2);// false
        System.out.println(s1.equals(s2));// true
    }
}
**运行结果:**

false 
true


内存分配图如下:


详解:

(1)、首先,通过main()方法进栈。
(2)、然后再栈中定义一个对象s1,s1由new创建,因此去堆中开辟一个内存空间,将内存空间的引用赋值给s1,“hello”是常量,然后去字符串常量池查看是否有hello字符串对象,没有的话分配一个空间存放hello,并且将其空间地址存入堆中new出来的空间中。
(3)、在栈中定义一个对象s2,s2不是由new创建,因此去字符串常量池中查看是否有”hello”字符串对象,有则直接把“hello”的地址赋值给s2。
(4)、即s1中存的是堆中分配的空间,堆中分配的空间中存的是字符串常量池中分配空间存放”hello”的空间的地址值。而s2中之中存的是字符串常量池中分配空间存放”hello”的空间的地址值。
(5)、由于s1与s2中存放的地址不同,所以输出false。因为,类String重写了equals()方法,它比较的是引用类型的 的值是否相等,所以输出true。即结果为false、true。


2、Deme2.

public class StringDemo4 {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        String s3 = "helloworld";
        System.out.println(s3 == s1 + s2);// false
        System.out.println(s3.equals((s1 + s2)));// true
        System.out.println(s3 == "hello" + "world");//true
        System.out.println(s3.equals("hello" + "world"));// true
    }
}
**运行结果:**
false
true
true
true
详解:

(1)、s1与s2相加是先在字符串常量池中开一个空间,然后拼接,这个空间的地址就是s1与s2拼接后的地址。与s3的地址不同,所以输出为false。
(2)、s3与”hello”+”world”作比较,”hello”+”world”先拼接成”helloworld”,然后再去字符串常量池中找是否有”helloworld”,常量池存在,所以和s3共用一个字符串对象,则为true。

总结:

(1)、String s = new String(“hello”)会创建2(1)个对象,String s = “hello”创建1(0)个对象。 
注:当字符串常量池中有对象hello时括号内成立!

(2)、字符串如果是变量相加,先开空间,在拼接。

(3)、字符串如果是常量相加,是先加,然后在常量池找,如果有就直接返回,否则,就创建。

(4)、对象用new创建时才在堆中分配空间,否则只在栈和常量池中分配空间。




Java 中,字符串常量池能够创建对象。当使用字符串字面量创建字符串时,如果字符串字面量不存在于字符串常量池中,JVM 会在字符串常量池中创建一个新的字符串对象。例如,`String s = "example";` 若 "example" 不在常量池,就会在常量池中创建该字符串对象。若字符串字面量已存在于字符串常量池中,JVM 会直接返回这个池中的引用,而不是重新创建一个新的字符串对象,这种机制减少了内存开销,还提高了字符串操作的效率 [^1]。 另外,在 JDK 7 以前,字符串常量池位于方法区,JDK 7 及以后,常量池移至堆内存。对于使用 `intern()` 方法,如果字符串常量池中没有该字符串的实例引用,会将首次出现的实例引用记录在常量池。如 `String s1 = new StringBuilder("ja").append("va").toString(); System.out.println(s1.intern() == s1);` 在 JDK 7 及以后返回 `true` 。若使用 `new` 关键字创建字符串对象,会在堆中创建一个新的字符串对象,调用 `intern()` 方法时,若常量池中没有对应的字符串,会在常量池添加对堆中该字符串对象的引用 [^3]。 ### 代码示例 ```java public class StringConstantPoolExample { public static void main(String[] args) { // 使用字符串字面量创建字符串 String str1 = "hello"; // 再次使用相同的字符串字面量 String str2 = "hello"; // 这里 str1 str2 引用常量池中的同一个对象 System.out.println(str1 == str2); // 使用 new 关键字创建字符串 String str3 = new String("world"); String str4 = str3.intern(); String str5 = "world"; // str4 str5 引用常量池中的同一个对象 System.out.println(str4 == str5); } } ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值