• 不就是Java吗之String类 PartI


    一、String的介绍

    C语言中,是没有字符串类型的,但是有字符串

    char* p = "hello";
    
    • 1

    Java中,是有字符串这种数据类型的,但是他不是所谓的以\0为结尾的,是通过长度判断字符串是否结尾

    二、常用方法

    2.1 字符串构造

    1. 使用常量串构造

      public class TestDemo1 {
          public static void main(String[] args) {
              //使用常量串构造
              String str1 = "hello";
              System.out.println(str1);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    2. 直接new String对象

      public class TestDemo1 {
          public static void main(String[] args) {
              //直接new String对象
              String str2 = new String("hello2");
              System.out.println(str2);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    3. 使用字符数组进行构造

      public class TestDemo1 {
          public static void main(String[] args) {
              //使用字符数组进行构造
              char[] array = {'h','e','l','l','o','3'};
              String str3 = new String(array);
              System.out.println(str3);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    注意:

    1. String是引用类型,内部并不存储字符串本身,其实底层就是数组

      image-20220606154254316

    2. 内存分配图

      public class TestDemo1 {
          public static void main(String[] args) {
              String str1 = new String("hello");
              String str2 = new String("world");
              String str3 = str1;
      
              System.out.println(str1);
              System.out.println(str2);
              System.out.println(str3);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      image-20220606154820236

      image-20220606155539670

    3. 两个方法

      1. s1.length():获取字符串长度

        注意:要带上后面的括号

        public class TestDemo1 {
            public static void main(String[] args) {
                String str1 = new String("hello");
        
                System.out.println(str1.isEmpty());
                System.out.println("hello".length());
            }
        }
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
      2. s1.isEmpty():如果字符串长度为0,返回true,否则返回false

        public class TestDemo1 {
            public static void main(String[] args) {
                String str1 = new String("hello");
        
                System.out.println(str1.isEmpty());
            }
        }
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8

    2.2 String对象的比较

    2.2.1 ==

    比较是否引用同一个对象

    对于内置类型,比较的是值是否相等

    对于引用类型,比较的是引用中的地址是否相同

    public class TestDemo2 {
        public static void main(String[] args) {
            //只要你进行new,就会开辟新的内存空间
            String str1 = new String("hello");
            String str2 = new String("hello");
            String str3 = new String("world");
    
            String str4 = str1;
    
            System.out.println(str1 == str2);//false
            System.out.println(str1 == str3);//false
            System.out.println(str1 == str4);//true
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.2.2 boolean equals(Object o)

    比较两个字符串是否相等:按照字典序进行比较

    字典序:就是按照字典中出现的先后顺序进行排序。

    String类重写了父类当中的equals方法,以前equals是按照地址进行比较的,被equals重写之后按照以下规则进行比较

    public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    image-20220606164654703

    这个方法的使用:

    public class TestDemo3 {
        public static void main(String[] args) {
            String str1 = new String("hello");
            String str2 = new String("hello");
            String str3 = new String("Hello");
    
            System.out.println(str1.equals(str2));//true
            System.out.println(str1.equals(str3));//false
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.2.3 int compareTo(String s)

    比较两个字符串的大小:按照字典序进行比较

    1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
    2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
    public class TestDemo4 {
        public static void main(String[] args) {
            String str1 = new String("abc");
            String str2 = new String("ac");
            String str3 = new String("abc");
            String str4 = new String("abcdef");
    
            System.out.println(str1.compareTo(str2));//-1 -> 不同输出字符差值-1
            System.out.println(str1.compareTo(str3));//0 -> 相同输出 0
            System.out.println(str1.compareTo(str4));//-3 -> 前k个字符完全相同,输出长度差值-3
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.2.4 int compareToIgnoreCase(String str)

    int compareTo(String s)相同,但是这个忽略大小写

    public class TestDemo4 {
        public static void main(String[] args) {
            String str1 = new String("abc");
            String str2 = new String("ac");
            String str3 = new String("abc");
            String str4 = new String("abcdef");
    
            System.out.println(str1.compareToIgnoreCase(str2));//-1 -> 不同输出字符差值-1
            System.out.println(str1.compareToIgnoreCase(str3));//0 -> 相同输出 0
            System.out.println(str1.compareToIgnoreCase(str4));//-3 -> 前k个字符完全相同,输出长度差值-3
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3 字符串查找

    2.3.1 char charAt(int index)

    返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常

    public class TestDemo1 {
        public static void main(String[] args) {
            String str = "hello";
            char ch = str.charAt(1);
            System.out.println(ch);//e
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意:下标必须合法

    image-20220606204512097

    2.3.2 int indexOf()

    四种形式:

    1. int indexOf(int ch):返回ch第一次出现的位置,没有返回-1
    2. int indexOf(int ch,int fromIndex):从fromIndex开始,返回ch第一次出现的位置,没有返回-1
    3. int indexOf(String str):返回字符串str第一次出现的位置,没有返回-1
    4. int indexOf(String str,int fromIndex):从fromIndex开始,返回str第一次出现的位置,没有返回-1
    public class TestDemo2 {
        public static void main(String[] args) {
            String str = "hello";
    
            int index1 = str.indexOf('h');
            System.out.println(index1);//0
    
            int index2 = str.indexOf('o',2);
            System.out.println(index2);//4
    
            int index3 = str.indexOf("ll");
            System.out.println(index3);//2
    
            int index4 = str.indexOf("ll",1);
            System.out.println(index4);//2
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.3.3 int lastIndexOf()

    四种形式:

    1. int lastIndexOf(int ch):从后往前找,返回ch第一次出现的位置,没有返回-1
    2. int lastIndexOf(int ch,int fromIndex):从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返
      回-1
    3. int lastIndexOf(String str):从后往前找,返回str第一次出现的位置,没有返回-1
    4. int lastIndexOf(String str,int fromIndex) :从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返
      回-1
    public class TestDemo3 {
        public static void main(String[] args) {
            String str = "hello";
    
            int index1 = str.lastIndexOf('h');
            System.out.println(index1);//0
    
            int index2 = str.lastIndexOf('l',4);
            System.out.println(index2);//3
    
            int index3 = str.lastIndexOf("ll");
            System.out.println(index3);//2
    
            int index4 = str.lastIndexOf("ll",4);
            System.out.println(index4);//2
            
            int index5 = str.lastIndexOf('l',2);//从2下标往前找->找不到->返回-1
            System.out.println(index5);//-1
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.4 转化

    2.4.1 数值和字符串转化

    public class TestDemo1 {
        public static void main(String[] args) {
            int a = 10;
            String str1 = String.valueOf(a);
            System.out.println(str1);//"10:
            System.out.println(str1 + 1);//"101" -> 能证明str变成字符串了
    
            System.out.println("---------------");
    
            String str2 = "1234";
            int num1 = Integer.valueOf(str2);
            int num2 = Integer.parseInt(str2);//跟上面那种是等价的
            double num3 = Double.valueOf(str2);//也可以转换成double类型的
    
            System.out.println(num1);//1234
            System.out.println(num2);//1234
            System.out.println(num3);//1234.0
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.4.2 大小写转换

    需要我们知道的是:大小写转换的操作的不是原数组,是把拷贝的数组进行大小写转换的

    public class TestDemo2 {
        public static void main(String[] args) {
            String str1 = "hello";
            String str2 = str1.toUpperCase();
            System.out.println(str2);//HELLO
    
            System.out.println("----------------");
    
            String str3 = "HELLO";
            String str4 = str3.toLowerCase();
            System.out.println(str4);//hello
    
            System.out.println("----------------");
    
            String str5 = "H_e!L#l%O";
            String str6 = str5.toLowerCase();//只会对字母起作用
            System.out.println(str6);//h_e!l#l%o
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.4.3 字符串转数组

    import java.util.Arrays;
    
    public class TestDemo3 {
        public static void main(String[] args) {
            String str1 = "hello";
            char chars[] = str1.toCharArray();
            System.out.println(Arrays.toString(chars));//[h, e, l, l, o]
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.4.4 格式化

    public class TestDemo4 {
        public static void main(String[] args) {
            String str = String.format("%d-%d-%d",2022,6,6);
            System.out.println(str);//2022-6-6
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.5 字符串替换

    使用一个指定的新的字符串替换掉已有的字符串数据

    regex替换成replacement

    1. String replace(String oldChar,String newChar):把oldChar替换成newChar
    2. String replaceAll(String oldChar,String newChar):替换所有的指定内容
    3. String replaceFirst(String oldChar,String newChar):替换第一个为oldChar的内容
    public class TestDemo5 {
        public static void main(String[] args) {
            String str1 = "abcdabcdabcd";
    
            String str2 = str1.replace("ab","li");//其实跟replaceAll一样
            System.out.println(str2);//licdlicdlicd
    
            String str3 = str1.replaceAll("ab","kj");
            System.out.println(str3);
    
            String str4 = str1.replaceFirst("ab","op");
            System.out.println(str4);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里,我们操作的也不是原数组.

    Java中,所有对字符串本身操作的函数,都不是在原来的字符串对象上进行的操作,因为字符串是不可变的

    2.6 字符串的拆分

    可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。

    1. String[] split(String regex):将字符串全部拆分
    2. String[] split(String regex,int limit):将字符串以指定的格式,拆分为limit
    public class TestDemo6 {
        public static void main(String[] args) {
            String str1 = "abc de f g";
            String[] strings = str1.split(" ");
            for (String s : strings) {
                System.out.println(s);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    image-20220606223532358

    拆分ip地址

    public class TestDemo6 {
        public static void main(String[] args) {
    
            String str2 = "162.190.1.1";
            String[] strings = str2.split("\\.",4);//最多分割为4组
            for (String string : strings) {
                System.out.println(string);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意事项:

    1. 字符"|“,”*“,”+"都得加上转义字符,前面加上 “\” .
    2. 而如果是 “\” ,那么就得写成 “\\” .
    3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符.

    举栗子:

    public class TestDemo6 {
        public static void main(String[] args) {
            String str3 = "Hello0606 english&888";
            String[] strings = str3.split(" |&");
            for (String string : strings) {
                System.out.println(string);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    public class TestDemo6 {
        public static void main(String[] args) {
            String str4 = "hello\\666";
            String[] strings = str4.split("\\\\");//\->\\ \\->\\\\
            for (String string : strings) {
                System.out.println(string);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    多次拆分:

    public class TestDemo6 {
        public static void main(String[] args) {
            String str5 = "name=zhangsan&age=18";
            String[] strings1 = str5.split("&");
            for (String str : strings1) {
                String[] strings2 = str.split("=");
                for (String str2 : strings2) {
                    System.out.println(str2);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.7 字符串的截取

    从一个完整的字符串之中截取出部分内容。

    1. String substring(int beginIndex):从指定索引截取到结尾
    2. String substring(int beginIndex,int endIndex):从beginIndex截取到endIndex
    public class TestDemo7 {
        public static void main(String[] args) {
            String str1 = "   abde sdfi  ";
            String ret1 = str1.substring(2,7);//from to -> 前闭后开 [2,7)
            System.out.println(ret1);// abde
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.8 trim()

    String trim():去掉字符串中的左右空格,保留中间空格

    public class TestDemo8 {
        public static void main(String[] args) {
            String str1 = "   abde sdfi  ";
            String ret2 = str1.trim();
            System.out.println(ret2);//abde sdfi->去掉左右两边空格,中间的不去掉
    		System.out.println(ret1);//   abde sdfi  ->证明了操作字符串操作的不是本身
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.9 字符串常量池

    我们先看这段代码

    public class demo_2_9 {
        public static void main(String[] args) {
            String str1 = "hello";
            String str2 = "hello";
            System.out.println(str1 == str2);//true
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我们的猜想是:两个字符串,实际上不是新new出来的吗?new出来的不就是新的吗?那不应该是false吗.但是答案是true

    我们继续看例子

    public class demo_2_9 {
        public static void main(String[] args) {
            String str1 = "hello";
            String str2 = "hello";
            String str3 = new String("hello");
            System.out.println(str1 == str2);//true
            System.out.println(str1 == str3);//false
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这时候,str1str3就不相等了.这是怎么回事呢?

    这一切都是字符串常量池搞的鬼.

    字符串常量池一般都在堆上

    image-20220607190718904

    image-20220607190355206

    特例:

    public static void main(String[] args) {
            String str1 = "hello";
            
            String ret = "he" + "llo";//在编译的时候,这里就直接认为是hello了
            System.out.println(str1 == ret);//true
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public static void main(String[] args) {
            String str1 = "hello";
    
            String str2 = "he";
            String str3 = "llo";
            String str4 = str2 + str3;//str2 str3是变量,在编译的时候,还不知道里面是谁
    
            System.out.println(str1 == str4);//false
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    记住,只要是new的,就是一定有新对象产生的

    2.9.1 intern方法

    public static void main(String[] args) {
            char[] ch = new char[]{'a','b','c'};
            String str = new String(ch);
            String str2 = "abc";
    
            System.out.println(str == str2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果为:false

    image-20220607192549625

    图解:

    image-20220607193401672

    加入intern之后:

    public static void main(String[] args) {
            char[] ch = new char[]{'a','b','c'};
            String str = new String(ch);
            str.intern();
    
            String str2 = "abc";
            System.out.println(str == str2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果是true

    image-20220607193600327

    str.intern()的作用是把str引用的对象手动入池(当常量池没有的时候)

    image-20220607194124114

    2.10 字符串的不可变性

    public static void main(String[] args) {
            String str = new String("hello");
            
        }
    
    • 1
    • 2
    • 3
    • 4

    我们ctrl+单击右面的String

    image-20220607194513518

    image-20220607194544878

    image-20220607194606586

    那么我们先来了解一下final

    public static void main(String[] args) {
            //String str = new String("hello");
            int[] arr = {1,2,3};
            arr = new int[]{1,2,3,4,5};
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样是不报错的,代表数组的指向可以改变

    加了final之后就报错了

    public static void main(String[] args) {
            //String str = new String("hello");
            final int[] arr = {1,2,3};
            arr = new int[]{1,2,3,4,5};
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20220607194823168

    代表array这个指向不能改变

    但是我们讲了这么多,String的不可变性跟这个没关.是因为数组是被private修饰的,而官方也没设计出他的get set方法,所以不能修改

    image-20220607195049350

    image-20220607200057864

    网上有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。

    这种说法是错误的,不是因为String类自身,或者其内部valuefinal修饰而不能被修改。是因为被private修饰了,根本拿不到字符串相关的函数来进行对字符串的操作,所以都是拷贝一个新数组来对新数组进行操作最后返回.

    image-20220607223553640

    2.11 字符串修改

    我们先来看一段代码

    public class TestDemo {
        public static void main(String[] args) {
            String str = "hello";
            str = str + "world";
            System.out.println(str);//helloworld
        }
    }
    
    
    //翻译如下
    public static void main(String[] args) {
            String str = "hello";
            //str = str + "world";
            //上面那行代码的翻译
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(str);
            stringBuilder.append("world");
            str = stringBuilder.toString();
            System.out.println(str);//helloworld
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    底层:
    image-20220607202021084

    如果我们再加上个"!!!"呢

    public class TestDemo {
        public static void main(String[] args) {
            String str = "hello";
            str = str + "world";
            str = str + "!!!";
            System.out.println(str);//helloworld!!!
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    image-20220607202326831

    比如我们举个栗子:

    public static void main(String[] args) {
            String str = "hello";
            for (int i = 0; i < 10; i++) {
                str += i;
            }
            System.out.println(str);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这样就会产生许多许多临时对象,不推荐

  • 相关阅读:
    GpsAndMap模块开源,欢迎测评
    一比一还原axios源码(一)—— 发起第一个请求
    C++_串口编程_官方示例:监视通信事件
    LeetCode每日一题——2558. Take Gifts From the Richest Pile
    rabbitmq-spring-boot-start配置使用手册
    Java并发编程学习12-任务取消(上)
    《牛客题霸-算法篇》刷题之NC111 最大数
    看球二三事 - 世界杯征文
    .NET8中的Microsoft.Extensions.Http.Resilience库
    python-sklearn模型通用方法的介绍
  • 原文地址:https://blog.csdn.net/m0_53117341/article/details/126091589