Java基础-String字符串

  • String是一种引用数据类型,是char的数组

  • String的值存储在字符串的常量池中,在JDK1.8中,字符串常量池存储于元空间中,JDK1.7中,字符串常量池存储于堆内存

  • 声明一个String类型的变量有两种方法

    • 直接赋值,使用这种方法声明的字符串栈内存中的指针直接指向字符串常量池中的值

      String str1 = "hello";
      
    • 创建String类的对象,使用这种方法声明的字符串栈内存中的指针指向堆内存中开辟的内存空间,之后再由堆内存指向字符串常量池中的值

      String str2 = new String("hello");
      
  • 字符串的比较

    • 直接赋值声明的两个字符串可以使用==来比较

      • 例如

        String str1 = "hello";
        String str2 = "hello";
        String str3 = "hi";
        System.out.println(str1 == str2);//结果为true
        System.out.println(str1 == str3);//结果为false
        
  • 在使用==比较使用创建String对象的方式声明的字符串时,即使它们的值相等,也可能出现结果为false的现象

    • 原因:String是引用数据类型,==比较的是左右两边的内存地址

    • 例如:

        String str1 = "hello";
        String str2 = new String("hello");
        System.out.println(str1 == str2);//结果为false
      

      输出的结果为false,两个字符串虽然值相同,但是声明的方式不同,在内存中存储的方式有所不同。比较时,实际上str1获取的地址是字符串常量池中值的地址,而str2获取的是堆内存中,String对象的地址,两个地址并不相同,因此结果为false。

        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1 == str2);//结果为false
      

      上述代码输出结果也为false,因为str1和str2虽然使用的声明方法相同,值也相同,但是两个独立String对象,在堆内存中开辟的内存地址不同。

  • 使用.equals方法可以直接比较两个字符串的值

    • 例如:

        String str1 = "hello";
        String str2 = new String("hello");
        System.out.println(str1.equals(str2));//结果为true
      
    • 原因:String类重写了equals方法,先比较两个字符串地址是否相同,如果相同返回true,如果不同判断传入的参数是否为String类型,如果不是返回flase,如果是那么进行值的一一比较。

    • String类中的equals方法源码

        public boolean equals(Object anObject) {
            //如果引用的是同一个对象,返回真
            if (this == anObject) {
                return true;
            }
            //如果不是String类型的数据,返回假
            if (anObject instanceof String) {
                String anotherString = (String) anObject;
                int n = value.length;
                //如果char数组长度不相等,返回假
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    //从后往前单个字符判断,如果有不相等,返回假
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                                return false;
                        i++;
                    }
                    //每个字符都相等,返回真
                    return true;
                }
            }
            return false;
        }
      
  • 字符串的拼接

    • 字符串直接可以使用+进行拼接

    • 例如:

      String str1 = "123";
      String str2 = "456";
      String str3 = str1 + str2;
      String str4 = "123" + "456";
      System.out.println(str3);//输出结果为123456
      System.out.println(str4);//输出结果为123456
      
    • 根据拼接方法的不同,使用==比较拼接过的字符串和一个值与其相同的字符串可能会有不同的结果

    • 使用变量名进行拼接

      • 例如:

        String str1 = "123";
        String str2 = "456";
        String str3 = str1 + str2;
        String str4 = "123456";
        System.out.println(str3 == str4);//结果为false
        

        使用这种拼接方法时,根据对.class文件的反编译可知,这样拼接字符串时实际上调用了StringBuilder的append方法,返回了一个String对象,因此结果为false。

        • 对样例代码的反编译结果

          public class Test {
            public Test();
              Code:
                 0: aload_0
                 1: invokespecial #1                  // Method java/lang/Object."<init>":()V
                 4: return
          
            public static void main(java.lang.String[]);
              Code:
                 0: ldc           #2                  // String 123
                 2: astore_1
                 3: ldc           #3                  // String 456
                 5: astore_2
                 6: new           #4                  // class java/lang/StringBuilder
                 9: dup
                10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
                13: aload_1
                14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
                17: aload_2
                18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
                21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
                24: astore_3
                25: ldc           #8                  // String 123456
                27: astore        4
                29: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
                32: aload_3
                33: aload         4
                35: if_acmpne     42
                38: iconst_1
                39: goto          43
                42: iconst_0
                43: invokevirtual #10                 // Method java/io/PrintStream.println:(Z)V
                46: return
          }
          
        • StringBuilder类的append方法源码

          public AbstractStringBuilder append(String str) {
              if (str == null)
                  return appendNull();
              int len = str.length();
              ensureCapacityInternal(count + len);
              str.getChars(0, len, value, count);
              count += len;
              return this;
          }
          
    • 使用值进行拼接

      • 例如

        String str1 = "123" + "456";
        String str2 = "123456";
        System.out.println(str1 == str2);//结果为true
        

        使用这中方法进行拼接时,通过对.class文件的反编译可知,在编译时,编译器对这种情况进行了优化,str1相当于直接赋值声明了一个值为123456的String类型变量

        • 对样例代码的反编译结果

          public class Test {
            public Test();
              Code:
                 0: aload_0
                 1: invokespecial #1                  // Method java/lang/Object."<init>":()V
                 4: return
          
            public static void main(java.lang.String[]);
              Code:
                 0: ldc           #2                  // String 123456
                 2: astore_1
                 3: ldc           #2                  // String 123456
                 5: astore_2
                 6: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
                 9: aload_1
                10: aload_2
                11: if_acmpne     18
                14: iconst_1
                15: goto          19
                18: iconst_0
                19: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
                22: return
          }
          
  • String类的常用方法

    1. 判断String的长度:length()方法

      • 样例

        public static void main(String[] args) {
                String str = "123456";
                int length = str.length();
                System.out.println(length);//6
            }
        
    2. 获取其中某一个值:charAt()方法

      • 参数是String中的某个字符的下标

      • 样例:

        public static void main(String[] args) {
                String astring = "123456";
                char a = astring.charAt(0);
                System.out.println(a);//1
            }
        
    3. 比较两个字符串的值是否相等:equals()方法

      • 样例

        public static void main(String[] args) {
                String str1 = "hello";
                String str2 = new String("hello");
                System.out.println(str1.equals(str2));//结果为true
            }
        
    4. 截取子串:subString()方法

      • 第一个参数是子串开始位置在原字符串的下标

      • 第二个参数是子串结束位置在原字符串的下标

      • 样例

            public static void main(String[] args) {
                String astring = "123456";
                System.out.println(astring.substring(3));//456
                System.out.println(astring.substring(3,5));//45
            }
        
posted @ 2020-12-18 22:38  00321001  阅读(82)  评论(0)    收藏  举报