String 类 : 字符串 -> 引用数据类型 (Java中最特殊的引用数据类型)
特点 :–
1、只要是双引号引起来的内容都是 String 类的对象 -> “hello”
-
2、字符串是Java中唯一一个不需要 new 就可以创建的对象 -> String str = “hello”;
-
3 、字符串是Java中唯一一个既是常量也是对象的 “东西”;
-
4. 字符串也是不能变的,如果改变字符串的内容那就一定生成了新的字符串 --> 所以字符串的拼接是非常消耗内存的; “Java” + “Hello” + “World” -> 解决问题 : StringBuilder/StringBuffer
-
5. 字符串可以共用的 (常量可以共用)
-
6. 字符串的本质是 一个字符数组; “abc” -> char[] chs = {‘a’,‘b’,‘c’};
-
7. 字符串的本本质是 一个字节数组: “abc” -> byte[] bys = {97,98,99};
-
8. 字符串是Java唯一一个可以做加法运算的对象 -> 加法是做拼接
-
==
==用于判断两个值或变量是否相等,对于基本数据类型来说,比较的是值是否相等,对于引用类型,比较的为在内存中的地址是否相同。 -
equals方法
equals 方法也用于比较值是否相等,他的底层结构仍然为 == ,因此在没有重写equals 方法的前提下,这两种比较方式得到的结果是一样的,但equals 方法在任何类中都能重写,也可以通过idea自动生成重写的 equals 方法,重写后不再比较地址值,而是比较的是两个变量的值是否相等。
在Java中,==可以理解为永远比较地址是否相同!
————————————————————————————————————————————
字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。
—————————————————————————————————————————————
String str1 = "1";
String str2 = "2";
String str3 = new String("1");
final String str4 = "2";
final String str5 = new String("2");
System.out.println("(1)"+ (str1 == str3));// 1. false
System.out.println("(2)"+ (str2 == str4));// 2. true
System.out.println("(3)"+ (str4 == str5));// 3. false
- str1 和 str2 都是直接赋值,常量池中如果有“1” 和 “2” ,则直接指向常量池中的对应地址,如果没有,则会在常量池中创建 “1” 和 “2” 对象,再由str1 和str2 指向。
- str3 采用new关键字赋值,则会由 new 关键字开辟出一片新的空间在堆空间中,假设为新开辟的空间地址为 0x001,若所赋的值在常量池中存在,则由0x001指向常量池的地址,若所赋的值在常量池中不存在,则会在常量池中新建所赋值的对象,再由0x001指向该对象地址。
- str4 由final关键字修饰,因此存储在常量池中,又因为常量池中已有“2”对象,因此 str2 和 str4 地址相同。
- str5 同样有final修饰,但 new String(“2”) 会在堆空间中开辟一片新的空间,因此即使有 final 修饰,str5 仍然保存在堆空间中,再由堆空间中的地址指向常量池。
String str6 = "12";
String str7 = "1" + "2";
String str8 = str1 + "2";
String str9 = str1 + str2;
String str10 = str3 + str4;
System.out.println("(4)"+ (str6 == str7)); // 4. true
System.out.println("(5)"+ (str6 == str8)); // 5. false
System.out.println("(6)"+ (str6 == str9)); // 6. false
System.out.println("(7)"+ (str6 == str10)); // 7. flase
- str6 同 str1 和 str2 一样,直接指向常量池地址。
- “1” 和 “2” 都在常量池中,所以对他们进行拼接的 str7 也保存在常量池中,又因为常量池中已有“12” ,所以 str7 的地址和 str6 相同。
- str1 为String类型的变量,“2”为字符串,变量和字符串做拼接的结果不会再保存在常量池中,而是在堆空间中重新开辟空间来存储,因此 str8 保存在堆空间中。
- 同理,str9也在堆空间中重新开辟内存空间进行存储。
- str10 中,str4 由final修饰,视为常量池中的常量,但 str3 为变量,因此也保存在对空间中。
String str11 = "1" + str4;
String str12 = "1" + str5;
String str13 = (str1 + str2).intern();
System.out.println("(8)"+ (str6 == str11)); // 8. true
System.out.println("(9)"+ (str6 == str12)); // 9. false
System.out.println("(10)"+ (str6 == str13)); // 10. true
-
“1” 和 str4 都在常量池中,因此 str11 的地址也保存在常量池中,和 str6 相同。
-
同理,str5 虽被final修饰,但也在堆空间中new了新空间保存,所以“1” 和 str5 拼接的结果保存在堆内存中。
-
借由intem()方法的作用,str13 的结果为 “12” ,在常量池中已经存在,所以 str13 的地址和 str6 相同。
intern()方法是一个本地方法,调用该方法时,如果字符串常量池中已经存在一个等于此String对象的字符串,就直接从常量池中返回这个字符串对象的引用,如果调用该方法的这个字符串对象,目前字符串常量池中还并不存在这个字符串对象,也就是说这个字符串对象是首次出现的,那么就新建并添加这个字符串对象到字符串常量池中, 并返回新建的字符串对象的引用。



