1.String对象特点
1.1对象相同,指向相同
String a = "GG";
String b = "GG";
System.out.println(a == b); //输出为true
以上图代码为例,在常量池创建一个"GG"的对象,栈中的 a 指向它,第二次创建同样的对象"GG"时,jvm直接先在常量池就里找"GG"的对象,并把指向对准它,所有两对象的指向地址相同,对象就相同。
1.2内容相同,指向未必相同
String a =new String("GG") ;
String b =new String("GG");
System.out.println(a == b); //输出为flase
a和b都是new出来的对象,它们的位置是在堆上,但位置是不同的,即a和b指向了堆内存不同的位置。简单来说,就是一模一样的双胞胎 = 同一个人吗?
1.3对象不可变
String a = "GG";
a = "MM";
a的对象内容从"GG"变成了"MM",是a的值发生了变化吗?
从"GG"变成了"MM",并不是改变了value值,而是重新创建了个"MM"的对象,并把a的指向指向了它。简单来说,就是张三生了个儿子李四,不幸夭折,生了第二个儿子,仍然叫李四,这个李四是复活了吗?
2.String对象特点的需求
2.1字符串常量池
是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。
简单来说,效率。
2.2保证哈希码(或者别的什么乱七八糟对象)的唯一性
Java容器中,如在hashMap 等容器中,存储对象是需计算HashCode,并以此得出该对象的存放位置。因此,当使用String对象存储时,可以放心地进行存储。
2.3安全性
Java中的URL,路径,或者密码大多是用String修饰存储。为什么?因为安全。
注意,String对象不可变 != final。
String类是用final关键字修饰,这说明String不可继承。
String底层维护了一个byte数组:
private final byte[] value;(JDK9中为byte数组)
该数组是用final修饰的,final修饰的字段创建以后就不可改变。
但是,为什么说String对象不可变 != final
final int[] value = {a,b,c};
int[] value2 = {d,e};
value = value2 //报错,说明String对象不可变
//但是,我如果修改数组的元素呢?
final int[] value = {a,b,c};
value[0] = 1;
System.out.println(value); //输出{1,b,c},String对象可变
//----为什么?
value用final修饰,value = value2 编译时,编译器不允许把value指向堆区另一个地址,但却可以改变其中元素,那么如何防止?
private,private final char value[]的private
用private禁止无权限的操作
所以,String是不可变的关键不仅仅是一个final。