深入理解String类(重点)

一、想要理解string类,先看源码:

1 public final class String
2     implements java.io.Serializable, Comparable<String>, CharSequence {
3     /** The value is used for character storage. */
4     private final char value[];
5 
6     /** Cache the hash code for the string */
7     private int hash; // Default to 0
8     ...
9 }

从上面可以看出

  • String类被final关键字修饰,意味着String类不能被继承,并且它的成员方法都默认为final方法;字符串一旦创建就不能再修改。
  • String类实现了Serializable、CharSequence、 Comparable接口。
  • String实例的值是通过字符数组实现字符串存储的。

二、String 方法

下面是 String 类支持的方法,更多详细,参看 Java String API 文档:

 三、字符串常量池

 在Java的内存分配中,总共3种常量池,分别是Class常量池、运行时常量池、字符串常量池。

字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性,常量池中一定不存在两个相同的字符串。

 1 public class String1 {
 2     static String a = "AB";
 3     static String b = "AB";
 4     static String c = new String("AB");
 5     static String d = "A"+"B";
 6     static String e = "A";
 7     static String f = "B";
 8     static String g = e+f;
 9     static String h = "A"+f;
10     public static void main(String[] args) {
11         System.out.println(a==b);   //true
12         System.out.println(a==c);   //false
13         System.out.println(a==d);   //true
14         System.out.println(a==g);   //false
15         System.out.println(a.equals(g));    //true
16         System.out.println(a.equals(h));    //true
17         System.out.println(a==h);   //false
18     }
19 }

内存分析如图所示:

四、关于字符串拼接符“+”

        把"java"、"language"和"specification"这三个字面量进行"+"操作得到一个"javalanguagespecification" 常量,并且直接将这个常量放入字符串池中,这样做实际上是一种优化,将3个字面量合成一个,避免了创建多余的字符串对象。而字符串引用的"+"运算是在Java运行期间执行的,即str + str2 + str3在程序执行期间才会进行计算,它会在堆内存中重新创建一个拼接后的字符串对象。总结来说就是:字符串常量"+"拼接是在编译期间进行的,拼接后的字符串存放在字符串池中;而字符串引用的"+"拼接运算实在运行时进行的,新创建的字符串存放在堆中。

对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"I"+"love"+"java"; 的字符串相加,在编译期间便被优化成了"Ilovejava"。对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。

五、、关于String.intern()

intern方法使用:一个初始为空的字符串池,它由类String独自维护。当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。

它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。

String.intern();
再补充介绍一点:存在于.class文件中的常量池,在运行期间被jvm装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,java查找常量池中是否有相同unicode的字符串常量,如果有,则返回其引用,如果没有,则在常量池中增加一个unicode等于str的字符串并返回它的引用。

例1:

 1 /**
 2  * 关于String.intern()
 3  */
 4 public void test11(){
 5     String s0 = "kvill"; 
 6     String s1 = new String("kvill"); 
 7     String s2 = new String("kvill"); 
 8     System.out.println("===========test11============");
 9     System.out.println( s0 == s1 ); //false
10     System.out.println( "**********" ); 
11     s1.intern(); //虽然执行了s1.intern(),但它的返回值没有赋给s1
12     s2 = s2.intern(); //把常量池中"kvill"的引用赋给s2 
13     System.out.println( s0 == s1); //flase
14     System.out.println( s0 == s1.intern() ); //true//说明s1.intern()返回的是常量池中"kvill"的引用
15     System.out.println( s0 == s2 ); //true
16 }

结果:false、false、true、true。

例2:

 1 public class String1 {
 2      
 3     public static void main(String[] args) {
 4         /**
 5          *      String a = "AB";
 6          *      String b = "AB";
 7          *      String c = new String("AB");
 8          *      String d = "A"+"B";
 9          *      String e = "A";
10          *      String f = "B";
11          *      String g = e+f;
12          *      String h = "A"+f;
13          *         System.out.println(a==b);   //true
14          *         System.out.println(a==c);   //false
15          *         System.out.println(a==d);   //true
16          *         System.out.println(a==g);   //false
17          *         System.out.println(a.equals(g));    //true
18          *         System.out.println(a.equals(h));    //true
19          *         System.out.println(a==h);   //false
20          */
21             String s1 = "AB";
22             String s2 = new String("AB");
23             String s3 = "A";
24             String s4 = "B";
25             String s5 = "A" + "B";
26             String s6 = s3 + s4;
27             System.out.println(s1 == s2);       //false
28             System.out.println(s1 == s5);       //true
29             System.out.println(s1 == s6);       //false
30             System.out.println(s1 == s6.intern());      //true
31             System.out.println(s2 == s2.intern());      //false  我的理解:左边s2=new String("AB");
32                                                         // 右边s2.intern()和String s2="AB"是一个意思,
33                                                         //所以两边不相等
34         }
35 }

内存分析:

 参考大神:https://blog.csdn.net/ifwinds/article/details/80849184

                   https://www.cnblogs.com/xiaoxi/p/6036701.html

             里面更加详细,想理解更深入,可以点击链接!!

猜你喜欢

转载自www.cnblogs.com/qiaoxin11/p/12551441.html