• 深入理解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实例的值是通过字符数组实现字符串存储的。

    二、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

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

  • 相关阅读:
    php中字符与字节的区别
    sql把两值之和当作条件进行查询
    Intel® Neural Compute Stick 2
    使用OpenCV的VideoCapture 读取.mp4文件时出现以下错误:Unable to stop the stream: Inappropriate ioctl for device
    更换Raspbian Buster源
    OpenCV之cv2函数 2
    OpenCV中cv2的用法
    OpenVINO 对象识别 real_time_object_detection Movidius
    树莓派和计算棒实现图形识别 RaspBerry Pi4 with OpenVino and Movidius
    树莓派无线网卡老是掉线
  • 原文地址:https://www.cnblogs.com/qiaoxin11/p/12551441.html
Copyright © 2020-2023  润新知