Java 字符串: String 的 new 操作和双引号直接赋值的区别
示例 1 :
public class Test {
public static void main(String[] args) {
String var0 = "China";
String var1 = new String("China");
String var2 = new String("Hi China");
System.out.println(var0 == var1); // false
System.out.println(var0.equals(var1)); // true
}
}
==: 比较的是地址值是否相同.
equals: String类型重写了 equals()方法,判断值是否相同.
疑问? var0、var1、var2 各创建了几个对象?
1. main 方法进栈
2. 在栈中定义对象 var0 , 去常量池中寻找”China”字符串对象, 未找到,在常量池中开辟一块儿内存空间存“China”,把地址赋给栈指针.
3. 在栈中定义对象 var1 , 去堆中开辟一个内存空间,将内存空间的引用赋值给 var1 ,“China”是常量,去常量池中获取“China”的空间地址存入堆中new出来的空间中.
4. 在栈中定义对象 var2 , 去堆中开辟一个内存空间,将内存空间的引用赋值给 var2 ,“Hi China”是常量,在常量池中未找到,随即在常量池中创建“Hi China”,将"Hi China”的空间地址,存入堆中new出来的空间中.
5. 到此.
var0 存的是常量池中分配空间存放”China”的空间的地址值.
var1 存的是堆中分配的空间,堆中分配的空间中存的是常量池中存放”China”的空间的地址值.
var2 存的是堆中分配的空间,堆中分配的空间中存的是常量池中存放”Hi China”的空间的地址值.
var0 与 var1 中存放的地址不同,所以 "==" 比较输出false, String 类重写了equals()方法,它比较的是引用类型的的值是否相等,所以输出true
答疑: var0 创建了1个对象.位于常量池中.
var1 创建了1个对象.位于堆中.
var2 创建了2个对象.分别位于堆中和常量池中.
示例2 :
public class Test2 {
public static void main(String[] args) {
String v0 = "Java8";
v0 = "Java11";
System.out.println(v0); //Java11
}
}
疑问? 会拼写Java的宝子们都知道字符串不可变的.可为何v0 从 "Java8" 变成了 "Java11"?有妖怪?
1. main 方法进栈
2. 在栈中定义对象 v0 , 去常量池中寻找”Java8”字符串对象, 未找到,在常量池中开辟一块儿内存空间存“Java8”,把地址赋给栈指针.
3. "Java11" 属于常量,去常量池中创建”Java11”字符串对象,将其空间地址付给 v0
4. v0 引用地址已更改为常量池中新创建的"Java11",所以输出“Java11”.
答疑: 所以,并不是将常量池中"Java8" 修改为 "Java11", 而是重新开辟一个空间存储"Java11"。仅引用改变.这就是String不可变的实现.
不可变的原因猜测:
1. 出于安全考虑,程序在运行之前虚拟机会把字符常量,静态变量等预加载到常量池(方法区) 中存储起来,在程序运行的时候直接调用,但是常量池里面的信息不会有重复的,每一个都是 唯一的(这样是为了减少内存的开销,提升性能),这些信息是线程共享的,同一个字符串可 能会被多个线程使用,如果字符串可变,当某个线程修对他做了修改,其他正在使用该字符串 的线程可能就会出现严重的错误,从而变得不安全。
2. 保证hash值不会经常变动,具有唯一性,使得类似HashMap的容器能实现key—value的功能
示例3 :
public class Test3 {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Java";
String s3 = "Hello"+"Java";
String s4 = s1 + "Java";
String s5 = s1 + s2;
String s6 = (s1 + s2).intern();
}
}
疑问? 变量相加(拼接) 和 常量相加有何区别?intern()什么作用?
1. main 方法进栈
2. s1、s2 直接在常量池中创建.
2. s3 属于常量相加, 编译优化会将 "Hello"+"Java" 变为 "HelloJava"后 在常量池中创建.
2. s4、s5 属于变量相加. 都在在堆中创建
2. s6 也属于变量相加. 但是使用了intern方法, 将不再堆中创建,而是跑到常量池中创建
答疑: 常量和常量的拼接,会在常量池中。但只要参与相加的项里面有变量,结果就在堆中。intern()作用就是将本该在堆中创建的变换到常量池中创建.
一文看懂Java中String的New操作和直接赋值字符串的区别
内容评价: 没有帮助 [ 0 ] , 有帮助 [ 0 ]
反馈
此页是否对您有帮助?