大部分的编程语言都有一个专门的类型表示字符串
在Java中,创建字符串有三种主要的形式
public class Test {
public static void main(String[] args) {
//第一种:hehe是一种字符串常量,用一个String类型的引用指向hehe
String str1 = "hehe";
//第二种:new了一个String对象
String str2 = new String("hehe");
//第三种:借助字符数组构建
char[] arr = {'a','b','c'};
String str3 = new String(arr)
}
}
第一种方式:hehe是一种字符串常量,用一个String类型的引用指向hehe
第二种方法:new了一个String对象
String str2 = new String(“hehe”);
相比方式1 多创建了一个额外的对象
第三种方法:两个对象,两个引用
Java中的字符串叫做不可变对象(对比数组).一旦把某个字符串对象创建好,这个字符串的内容就不能修改了,实在想改只能创建新的字符串对象。(String 类没有提供类似set方法这样的操作来修改String对象的内容)
int[] arr = {1,2,3};
int[] arr2 = arr;
arr2[0] = 100;
System.out.println(arr[0]);
输出结果为100
public class Test {
public static void main(String[] args) {
String str1 = "hehe";
String str2 = str1;
str1 = "world";
System.out.println(str2);
}
}
输出结果是 hehe
因为 str1 str2 都指向 “hehe”这个对象
修改str1让它指向world,str2也是指向hehe,所以并没有影响.
2.字符串比较相等
String str1 = "hehe";
String str2 = "hehe";
if(str1 == str2){
System.out.println("相等");
}else {
System.out.println("不想等");
}
相等
因为“hehe”,都是字符串常量,实际上只有一份,str1和str2都指向它,所以输出结果
String str1 = "hehe";
String str2 = new String("hehe");
if(str1 == str2){
System.out.println("相等");
}else {
System.out.println("不相等");
}
不相等
java中用 == 针对引用类型比较的是对象的身份(两个引用是不是对应同一个对象)。
如果想比较两个字符串的值,用equals方法,或者使用compareTo方法也行。
str1.equals(str2)
“hehe"这样的字符串常量存在一个内存的特殊区域中,称为"字符串常量池”(本质上是堆中的一个区域)
如何在池中查找值为"hello"对象?哈希表
如何把new出来的String对象放入池子中
String str2 = new String("hehe").intern();
//此时str2指向的是池中的对象
intern做的事情:
1.查找当前这个字符串是否在常量池中包含,根据哈希表查找形式
2.如果包含了,直接返回池中的对象的引用
3.如果没包含,那就根据当前这个对象的值,在池中构造一个相同值的新的对象,并返回这个池里的引用。
面试题:请解释String类中两种对象实例化的区别
1.直接赋值:只开辟了一块堆内存空间,并且该字符串对象可以自动保存在对象池中供下次使用
2.构造方法:会开辟两块堆内存空间,其中一块保存在对象池中,可以使用intern()方法手工让他进入池。
字符串是不可变对象
String str1 = "hello";
str1 = str1 + "world";
str1 += "!!!";
System.out.println(str1);
其中有三个在池子里,hello world !!! 有一个是垃圾
通常情况下,字符串是不可变对象,如果实在要修改,需要创建新的字符串对象
通过特殊手段修改字符串内容
反射
import java.lang.reflect.Field;
public class Test2 {
public static void main(String[] args) {
String str = "hehe";
try {
//1.获取到value这个字段对应的对象。
Field valueField = String.class.getDeclaredField("value");
//2.让value对应的对象可以被访问到,强行破坏封装
valueField.setAccessible(true);
//3.根据我们的valueField 对象和str对象,找到str中的value
char[] value = (char[])valueField.get(str);
//4.修改value
value[0] = 'a';
System.out.println(str);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
为什么String要不可变
1.方便实现字符串对象池,如果String可变,那么对象池就需要考虑何时深拷贝字符串的问题了
2.不可变对象是线程安全的。
3.不可变对象更方便缓存hash code,作为key时可以更高效的保存到HashMap中