Java中String类的基本使用

1. String概述

  • 字符串就是多个字符连起来组成的一串数据.
  • 字符串的本质是一维字符数组.
  • 字符串字面值( 例如"abc" ) 可以看作一个字符串对象.
  • 字符串是常量, 一旦赋值, 值不能改变, 但是引用可以改变.
    (StringBuffer和String差不多, 但是StringBuffer的值是可变的, 解决了String浪费内存的问题. )

#2. String的常用构造方法

  • 此处只讨论常用构造, 实际上String的构造不只下面例举的.
  1. public String():无参构造.
  2. public String(byte[] bytes):字节数组转字符串.
  3. public String(byte[] bytes,int offset,int length):字节数组的一部分转字符串. 将字节数组bytes从索引offset开始的length个字节转换成字符串.
  4. public String(char[] value):字符数组转字符串.
  5. public String(char[] value,int offset,int count): 字符数组的一部分转字符串. 将字符数组value从索引offset开始的count个字符转换成字符串.
  6. public String(String original): 字符串常量转字符串.
  7. public String(StringBuffer buffer): StringBuffer 转 String.
  8. public String(StringBuilder builder):StringBuilder 转 String .
    /**
     * public String ():空构造。
     */
    @Test
    public void test01() {
        String s = new String();
        System.out.println(s); // 输出 空
        System.out.println(s.length()); // 0
    }

    /**
     * String(byte[] bytes):把字节数组转换成字符串。
     */
    @Test
    public void test02() {
        // 字节的取值是 -128~127
        byte[] bytes = {97, 98, 99, 100, 101};
        String s = new String(bytes);
        System.out.println(s.toString()); // abcde
        System.out.println(s.length()); // 5

        /*
         * 我们写的是97, 98, 99, 100, 101, 输出的却是abcde, 这是因为97代表ASCII码中的a.
         * 将byte数组转换为字符串, 需要先把byte转换成字符.
         *
         * 另外,
         * 48 0
         * 65 A
         * 97 a
         */
    }

    /**
     * String(byte[] bytes, int offset, int length):把字节数组的一部分转换成字符串。
     */
    @Test
    public void test03() {
        byte[] bytes = {97, 98, 99, 100, 101};
        String s = new String(bytes, 2, 2);
        System.out.println(s); // cd
        System.out.println(s.length()); // 2
    }

    /**
     * String(char[] value):把字符数组转换成字符串。
     */
    @Test
    public void test04() {
        char[] chars = {'a', 'b', 'c', 'd', '你', '好'};
        String s = new String(chars);
        System.out.println(s); // abcd你好
        System.out.println(s.length()); // 6
    }

    /**
     * String(char[] value, int offset, int count):把字符数组的一部分转换成字符串。
     */
    @Test
    public void test05() {
        char[] chars = {'a', 'b', 'c', 'd', '你', '好'};
        String s = new String(chars, 2, 3);
        System.out.println(s); // cd你
        System.out.println(s.length()); // 3
    }

    /**
     * String(String original):把字符串常量转换成字符串。
     */
    @Test
    public void test06() {
        // 在java中,字符串字面值"abc"也可以看成是一个字符串对象.
        String s = "abc";
        System.out.println(s); // abc
        System.out.println(s.length()); // 3

        String s1 = new String("abc"); 
        System.out.println(s1); // abc
        System.out.println(s1.length()); // 3
        // 实际上, String s1 = new String("abc");这个构造的意义不大.
    }

3. 字符串一旦赋值就不能被改变

    @Test
    public void test01(){
        String s1 = "abc";
        s1 = "def";

        /*
         * 上述两行实际上是没错的.
         * "字符串一旦赋值不能被改变"指的是
         * 字符串对象不能变, 但是这个对象的引用变量能变. 
         * 
         * 上述代码中, 字符串对象是"abc"和"def", 对象的引用是s1. 
         * 
         * s1相当于是绑气球的线, 先绑到"abc"这个气球上, 
         * 又绑到了"def"这个气球上. 气球本身并没有改变. 
         */
    }

在这里插入图片描述
在这里插入图片描述
注意, 只有使用直接赋值的方式创建字符串对象( 例如: String s = “abc”; )才能对应上面的内存描述.

3. 字符串字面值对象和构造方法创建的对象的区别

  • 问题:String s=new String ("abc");String s="abc";的区别。
    在这里插入图片描述

  • String s1 = new String(“hello”); 时, 先在常量池创建"hello"对象, 因为"hello"是字符串字面量, 字面量形式声明的字符串都是字符串对象,这个对象存储在常量池中. 接着, 在堆内存中new String(); 然后堆内存中的该对象指向常量池中的"hello"对象, 相当于使用常量池中的"hello"给堆内存中的new String();的成员变量赋值.

  • String s2 = “hello”;时, 由于是字面量形式创建的String对象, 那么先去常量池中找是否有"hello"对象, 如果有, 就将常量池中"hello"对象的地址值赋值给引用变量s2. 如果常量池中没有"hello"对象, 那么就在常量池中创建一个"hello"对象之后再将该对象的地址值赋值给引用变量s2.

  • 综上

    /**
     * String s1 = new String("hello"); 这句实际上是先在常量池中创建"hello"对象,
     * 然后在堆内存中创建new String();对象,
     * 然后将常量池中的"hello"赋值给new String();的成员变量. 因此这句实际上创建了两个对象.
     */
    @Test
    public void test03(){
        String s1 = new String("hello");
        String s2 = "hello";
    }
    
    /**
     * String s1 = new String("hello");
     * 这句实际上是在堆内存创建了一个new String()对象,然后该对象指向了常量池中的
     * "hello"对象. 在new String("hello");之前, 常量池中就已经存在"hello"对象了.
     */
    @Test
    public void test03() {
        String s2 = "hello";
        String s1 = new String("hello");
    }
    
  • String s1 = "abc"; 和直接写 "abc" 的区别
    在这里插入图片描述

  • 小结

    • 字面值常量是存放到方法区的常量池中的. 字符串的字面值常量是字符串对象.

4. 常量优化机制

在这里插入图片描述

  • String s1 = “hello”; 中, "hello"是字符串字面量, String s1 = “hello”; 整体是变量.
	// 不只字符串常量有常量优化机制.所有数据类型的常量都有常量优化机制
    @Test
    public void test04(){
        byte b = 10 + 20;
        /*
         * 上述的代码正确.
         * 因为在编译时走了常量优化机制,也就是最终优化的结果为byte result = 30; 符合数据类型范围
         */

        byte b1 = 10;
        byte b2 = 20;
        byte result1 = b1 + b2; // 这句编译报错 
        /*
         * 上述的 byte result1 = b1 + b2; 编译错误. 
         * 俩个变量在编译时不确定里面的值,因为变量有可能发生改变,所以无法再编译阶段时对变量进行优化
         */
    }
    @Test
    public void test10() {
        String s1 = "ab";
        System.out.println(s1 + "c" == "abc"); // false
        // 其中s1不是常量而是对象, 因此不会走常量优化机制. 返回false.
        /*
         * 字符串中有变量相加, 先开辟一块内存, 再拼接字符串,
         * 都开辟新的内存了, 肯定返回false
         */
    }

    @Test
    public void test11() {
        String s1 = "ab";
        String s2 = "c";
        System.out.println(s1 + s2 == "abc"); // false
        // 由于s1和s2都不是常量, 都是对象, 因此不走常量优化机制. 返回false.
        /*
         * 字符串中有变量相加, 先开辟一块内存, 再拼接字符串,
         * 都开辟新的内存了, 肯定返回false
         */
    }
  • 两个字面值常量相加, 例如"ab"+"c"="abc", 实际上是将"ab"+"c"的结果"abc"存储到常量池中, 这就是常量优化机制. 因此System.out.println("ab" + "c" == "abc");返回true.
    上述说的将结果存储到常量池中的过程, 也是先到常量池中找有没有这个结果, 如果有就直接引用这个结果, 如果没有, 就在常量池中创建这个结果.

5. String中的常用方法

5.1 String的判断功能

  1. boolean equals (Object obj); 比较字符串内容是否相同,区分大小写. 常用
  2. boolean equalsIgnoreCase(String str); 比较字符串内容是否相同,忽略大小写. 常用
  3. boolean contains(String str); 判断大字符串中是否包含小字符串. 常用
  4. boolean startsWith(String str); 判断字符串是否以某个指定的字符串开头.
  5. boolean endsWith(String str); 判断字符串是否以某个指定的字符串结尾.
  6. boolean isEmpty(); 判断字符串数据是否为空. 常用
    /**
     * boolean contains(String str);
     * 判断大字符串中是否包含小字符串
     */
    @Test
    public void test01() {
        String s1 = "helloworld";
        System.out.println(s1.contains("hello"));//t
        System.out.println(s1.contains("hw"));//f
    }

    /**
     * boolean startsWith(String str);
     * 判断字符串是否以某个指定的字符串开头
     */
    @Test
    public void test02(){
        String s1="helloworld";
        System.out.println(s1.startsWith("hel"));//t
        System.out.println(s1.startsWith("rld"));//f
    }

    /**
     * boolean isEmpty();
     * 判断字符串数据是否为空。
     * 
     * 字符串内容为空:对象存在,没有数据。String s="";
     * 字符串对象为空:对象都不存在。String s=null;
     */
    @Test
    public void test03(){
        String s1="";
        String s2="hello";
        String s3=null;
        System.out.println(s1.isEmpty());//t
        System.out.println(s2.isEmpty());//f
        System.out.println(s3.isEmpty());//空指针异常
    }

5.2 String的获取功能

  1. int length(); 获取字符串的长度.
  2. char charAt(int index); 获取指定索引位置的字符.
  3. int indexOf(int ch); 返回指定字符在此字符串中第一次出现的索引.
    方法的参数, 写 ‘a’ 或 97 都可以. Ascii码中, 97就代表’a’.
  4. int indexOf(String str); 返回指定字符串在此字符串中第一次出现的索引.
  5. int indexOf(int ch,int fromIndex); 返回指定字符在此字符串中从指定位置后第一次出现的索引.
  6. int indexOf(String str,int fromIndex); 返回指定字符串在此字符串中从指定位置后第一次出现的索引.
  7. String substring(int start); 从指定位置截取字符串,默认到末尾.
  8. String substring(int start,int end); 从指定位置截取字符串,从指定位置结束截取. 包左不包右
    /**
     * int length(); 获取字符串的长度.
     */
    @Test
    public void test01() {
        String s1 = new String();
        System.out.println(s1.length()); // 0

        s1 = "qwerty";
        System.out.println(s1.length()); // 6

        String s2 = null;
        System.out.println(s2.length()); // java.lang.NullPointerException

        String s3 = "abc";
        System.out.println(s3.length()); // 3

        System.out.println("hello world".length()); // 11

        /*
         * 注意,
         * String s1 = new String();
         * s1的长度是0.
         *
         * String s2 = null;
         * 获取s2的长度将报错空指针异常.
         */
    }
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 14:44
     * @param: []
     * @return: void
     * @description: int indexOf(int ch);  返回指定字符在此字符串中第一次出现的索引.
     */
    @Test
    public void test01() {
        String s1 = "qwerty";
        System.out.println(s1.indexOf('e')); // 2
        System.out.println(s1.indexOf(101)); // 2
    } 
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 14:44
     * @param: []
     * @return: void
     * @description: int indexOf(int ch); 返回指定字符在此字符串中第一次出现的索引.
     * 为什么参数需要的是int类型而不是char类型呢? 这是由于在ASCII码中'a'和97都能表示'a'.
     * 实际上, 参数中既能传入字符类型, 也能传入int类型.
     */
    @Test
    public void test01() {
        String s1 = "qwerty";
        System.out.println(s1.indexOf('e')); // 2
        System.out.println(s1.indexOf(101)); // 2

        System.out.println("a"); // -1 
        System.out.println(s1.indexOf(10000000)); // -1 
    }
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 15:00
     * @param: []
     * @return: void
     * @description: int indexOf(String str)
     *  返回指定字符串在此字符串中第一次出现的索引
     */
    @Test
    public void test01() {
        String s="helloworld";
        System.out.println(s.indexOf("or")); // 6
        System.out.println(s.indexOf("abc")); // -1 
    }
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 15:06
     * @param: []
     * @return: void
     * @description: int indexOf(int ch,int fromIndex); 
     *  返回指定字符在此字符串中从指定位置后第一次出现的索引
     */
    @Test
    public void test01() {
        String s = "helloworld";
        // 在索引为4的字符后, 查找字符'l'第一次出现的索引
        System.out.println(s.indexOf('l', 4)); // 8
        // 在索引为4的字符后, 查找字符'k'第一次出现的索引
        System.out.println(s.indexOf('k', 4)); // -1
        // 在索引为40的字符后, 查找字符'h'第一次出现的索引
        System.out.println(s.indexOf('h', 40)); // -1
    }
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 15:33
     * @param: []
     * @return: void
     * @description: String substring(int start,int end);
     * 从指定位置截取字符串,从指定位置结束截取; (包左不包右)
     */
    @Test
    public void test01(){
        String s="helloworld";
        System.out.println(s.substring(5)); // world
        System.out.println(s.substring(5,8)); // wor 
    }
  • 练习
/*================================字符串的遍历================================*/
    /**
     * 字符串的遍历方式1:
     * int length(); 方法 + char charAt(int index); 方法
     */
    @Test
    public void test01() {
        String s = "helloworld";
        for (int i = 0; i < s.length(); i++) {
            System.out.print(s.charAt(i) + "\t");
        }
        // h	e	l	l	o	w	o	r	l	d
    }

    /**
     * 字符串的遍历方式2:
     * byte[]getByte();方法
     */
    @Test
    public void test02() {
        String s = "helloworld";
        byte[] bytes = s.getBytes();
        for (int i = 0; i < bytes.length; i++) {
            System.out.print(bytes[i] + "\t");
        }
        // 输出: 104 101 108 108 111 119 111 114 108 100

        for (int i = 0; i < bytes.length; i++) {
            System.out.print((char) bytes[i] + "\t");
        }
        // 输出: h	e	l	l	o	w	o	r	l	d
    }
/*=======================统计字符串中的大写,小写,数字各有几个=======================*/
    @Test
    public void test01() {
        String s = "HelloWorld123";
        int bigCount = 0,
                smallCount = 0,
                numberCount = 0;
        for (int a = 0; a < s.length(); a++) {
            char x = s.charAt(a);
            if (x >= '0' && x <= '9') numberCount++;
            if (x >= 'a' && x <= 'z') smallCount++;
            if (x >= 'A' && x <= 'Z') bigCount++;
        }
        
        System.out.println(
                "大写: "+bigCount+"个; \n " +
                "小写: "+smallCount+"个; \n " +
                "数字: "+numberCount+"个; "
        );
    }

5.3 String的转换功能

  1. byte[] getBytes(); 把字符串转换为字节数组.
  2. char[] toCharArray(); 把字符串转换为字符数组.
  3. static String valueOf(char[] chs); 字符数组转字符串.
  4. static String valueOf(数据类型 变量名); 任意数据类型转字符串.
  5. String toLowerCase(); 字符串转小写.(产生了新的全小写字符串,原字符串未变)
  6. String toUpperCase(); 字符串转大写.(产生了新的全大写字符串,原字符串未变)
  7. String concat(String str); 拼接字符串.
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 16:57
     * @param: []
     * @return: void
     * @description:
     * toUpperCase(); 字符串转大写;
     * toLowerCase(); 字符串转小写; 
     */
    @Test
    public void test01() {
        String s = "QQqqQQqqQq";
        String newStr1 = s.toUpperCase();
        String newStr2 = s.toLowerCase();
        System.out.println(newStr1); // QQQQQQQQQQ
        System.out.println(newStr2); // qqqqqqqqqq
        System.out.println(s); // QQqqQQqqQq
    }
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 17:02
     * @param: []
     * @return: void 
     * @description: String concat(String str): 拼接字符串
     */
    @Test
    public void test01() {
        System.out.println("-------拼接字符串的第一种方式-------");
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("hello");
        stringBuffer.append("world");
        System.out.println(stringBuffer.toString());
        System.out.println("------------------------");

        System.out.println("-------拼接字符串的第二种方式-------");
        String s1 = "hello";
        String s2 = "world";
        System.out.println(s1 + s2);
        System.out.println("------------------------");

        System.out.println("-------拼接字符串的第三种方式-------");
        String s3 = s1.concat(s2);
        System.out.println(s3);
        System.out.println("------------------------");
    } 
	// 推荐只使用第一种方式. 
  • 练习
    /**
     * @author: wjl@king.cn
     * @createTime: 2019/12/3 17:08
     * @param: []
     * @return: void
     * @description: 把字符串的首字母转换成大写, 其他的字符全部转换成小写.
     * 步骤:
     * 1、获取第一个字符
     * 2、获取除了第一个字符以外的字符
     * 3、把1转大写
     * 4、把2转小写
     * 5、3拼4
     */
    @Test
    public void test() {
        String target = "helloJavaWorldPHP";
        String first = target.substring(0, 1);
        String other = target.substring(1);
        String newFirst = first.toUpperCase();
        String newOther = other.toLowerCase();
        String newStr = newFirst + newOther;
        System.out.println(newStr);
    }

5.4 String的其他功能

5.4.1 替换功能

  1. String replace(char old,char new);
  2. String replace(String old,String new);
  3. String replaceAll(String regex,String replacement);

5.4.2 去除字符串首尾空格

  1. String trim();

5.4.3 按字典顺序比较两个字符串

  1. int compareTo(String str);
  2. int compareToIgnoreCase(String str);
    public static void main(String[] args) {
        // h: 104
        // e: 101
        // l: 108
        // o: 111
        // q: 113
        // w: 119
        // r: 114
        // c: 99
        String s1 = "hello";
        String s2 = "hello";
        String s3 = "qwer";
        String s4 = "hcllo";
        
        /*A*/
        System.out.println(s1.compareTo(s2));//0
        /*B*/
        System.out.println(s1.compareTo(s3));//-9
        /*C*/
        System.out.println(s1.compareTo(s4));//2
    }

    //A:相同字符的ASCII码值相减。
    //B:h和q的ASCII码值相减。
    //C:e和c的ASCII码值相减。

    /*
    从第一个字符开始比较,他们的ASCII码值相减,如果都一样就输出0,
    发现第一个不一样的字符输出他们的ASCII码值的差。
    */
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hel";
        System.out.println(s1.compareTo(s2)); // 2
        //2
    }
    // 这种类型的比较返回的是长度相减 

5.5 String和字符集编码相关的方法

  1. String(byte[] bytes, String charsetName); 使用指定的字符集,将字节数组变成字符串. 这是String的一个构造方法.
  2. getBytes(String charsetName); 使用指定的字符集,将字符串变成字节数组. 该方法有多个重载的方法.

5.6 String和正则表达式相关的方法

  • String中有3个和正则表达式相关的方法
  1. boolean matches(String regex); 判断当前字符串是否和参数正则表达式匹配.
  2. String[] split(String regex); 使用指定的正则表达式切割当前字符串.
  3. String replaceAll(String regex, String newStr); 将调用者字符串中的所有匹配regex正则的子串,全部替换成newStr新串.
  • public boolean matches(String regex) 方法的使用
package cn.king.demo01;
import java.util.Scanner;

/*
 * public boolean matches(String regex):
 * 判断当前字符串是否和参数正则表达式匹配。
 */

/**
 * 使用正则表达式校验qq号码:
 * 1、要求必须是5-15位数字
 * 2、0不能开头
 * 
 * 分析:
 * a:键盘录入一个qq
 * b:写一个功能校验qq
 * c:调用功能输出结果
 */
public class Demo01 {
    public static void main(String[] args) {
        System.out.println("输入QQ: ");
        String qq = new Scanner(System.in).nextLine();
        System.out.println(checkQQ(qq));
    }

    public static boolean checkQQ(String qq) {
        return qq.matches("[1-9][0-9]{4,14}");
    }
}

/*
 * 同理, 校验手机号只需要更换正则表达式即可,
 * String regexForPhone="1[38]\\d{9}";
 * 同理, 校验邮箱只需要更换正则表达式即可,
 * String regexForMail = "\\w+@\\w{2,6}(\\.\\w{2,3})+";
 */
  • public String[] split(String regex) 方法的使用
package cn.king.demo01;
/**
 * public String[] split(String regex):
 * 使用指定的正则表达式切割当前字符串。
 */
public class Demo02 {
    public static void main(String[] args) {
        String s1 = "aa,bb,cc";
        // 将字符串按照逗号分隔, 分隔出的每一部分都放到字符串数组中
        String[] str1Array = s1.split(",");
        for (int x = 0; x < str1Array.length; x++) {
            System.out.println(str1Array[x]);
        }
        System.out.println("---------------------");

        // 将字符串按照点分隔, 分隔出的每一部分都放到字符串数组中
        String s2 = "aa.bb.cc";
        String[] str2Array = s2.split("\\.");
        for (String item : str2Array) {
            System.out.println(item);
        }
        System.out.println("---------------------");

        String s3 = "aa    bb                cc";
        // 将字符串按照点分隔, 分隔出的每一部分都放到字符串数组中
        String[] str3Array = s3.split(" +");
        for (String value : str3Array) {
            System.out.println(value);
        }
        System.out.println("---------------------");

        // 硬盘上的路径,我们应该用\\替代\
        String s4 = "E:\\JavaSE\\day14\\avi";
        // 将字符串按照\\分隔, 分隔出的每一部分都放到字符串数组中
        String[] str4Array = s4.split("\\\\");
        for (String s : str4Array) {
            System.out.println(s);
        }
        System.out.println("---------------------");
    }
}
	// 注意下面这种方式, 我们给split();方法的参数传递空字符串, 那么返回的是字符串数组. 
	public static void main(String[] args) {
        String str = "hello world";
        String[] strArr = str.split("");
        // [h, e, l, l, o,  , w, o, r, l, d]
        System.out.println(Arrays.toString(strArr));
    }
package cn.king.demo01;
import java.util.Arrays;

/*
 * 我有如下一个字符串:"91 27 46 38 50"
 * 请写代码实现最终输出结果是:"27 38 46 50 91"
 *
 * 分析:
 * 		A:定义一个字符串
 * 		B:把字符串进行分割,得到一个字符串数组
 * 		C:把字符串数组变换成int数组
 * 		D:对int数组排序
 * 		E:把排序后的int数组在组装成一个字符串
 * 		F:输出字符串
 */
public class Demo03 {
    public static void main(String[] args) {
        // 定义一个字符串
        String s = "91 27 46 38 50";

        // 把字符串进行分割,得到一个字符串数组
        String[] strArray = s.split(" ");

        // 把字符串数组变换成int数组
        int[] arr = new int[strArray.length];

        for (int x = 0; x < arr.length; x++) {
            arr[x] = Integer.parseInt(strArray[x]);
        }

        // 对int数组排序
        Arrays.sort(arr);

        // 把排序后的int数组在组装成一个字符串
        StringBuilder sb = new StringBuilder();
        for (int x = 0; x < arr.length; x++) {
            sb.append(arr[x]).append(" ");
        }
        //转化为字符串
        String result = sb.toString().trim();

        //输出字符串
        System.out.println("result:" + result);
    }
}
  • String replaceAll(String regex, String newStr) 方法的使用
package cn.king.demo01;
/**
 * String replaceAll(String regex, String newStr) :
 * 将调用者字符串中的所有匹配regex正则的子串,全部替换成newStr新串
 */
public class Demo04 {
    public static void main(String[] args) {
        String s = "helloqq12345worldkh622112345678java";

        // 使用"*"替换所有的数字. 
        // 输出: helloqq*worldkh*java
        System.out.println(s.replaceAll("\\d+", "*"));
        // 输出: helloqq*****worldkh************java
        System.out.println(s.replaceAll("\\d","*")); 

        // 直接把数字删除. 使用空字符串替换数字即可.
        String result = s.replaceAll("\\d+", "");
        System.out.println(result);
    }
}
    /**
     * 模拟简单的敏感词过滤.
     * 如果parameter中包含list中的敏感词, 那么将parameter的这些敏感词替换为"*"
     */
    public static void main(String[] args) {
        String parameter = "史蒂夫笨蛋史蒂夫笨蛋史蒂夫笨蛋史蒂夫笨蛋史蒂夫笨蛋";
        List<String> list = new ArrayList<>();
        list.add("笨蛋");
        list.add("狗屎");
        for (String s: list){
            if (parameter.contains(s)) {
                StringBuilder newStr = new StringBuilder();
                for (int i = 0; i < s.length(); i++) {
                    newStr.append("*");
                }
                parameter = parameter.replaceAll(s, newStr.toString());
            }
        }
        // 史蒂夫**史蒂夫**史蒂夫**史蒂夫**史蒂夫**
        System.out.println(parameter);
    }

6. String相关练习

  • 把数组中的数据按照指定格式拼接成一个字符串
    /**
     * 数组:String[] strArr = {"java", "php", "python"};
     * 输出:[java,php,python]
     */
    @Test
    public void test() {
        String[] strArr = {"java", "php", "python"};
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("[");
        for (int i = 0; i < strArr.length; i++) {
            if (i == strArr.length - 1) {
                stringBuffer.append(strArr[i]);
            } else {
                stringBuffer.append(strArr[i]);
                stringBuffer.append(",");
            }
        }
        stringBuffer.append("]");
        String s = stringBuffer.toString();
        System.out.println(s); // [java,php,python]
    }
  • 字符串翻转
    /**
     * 字符串反转. 
     * 只需要倒序遍历即可. 
     */
    @Test
    public void test01() {
        String s = "abc";

        char[] charArray = s.toCharArray();
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = charArray.length - 1; i >= 0; i--) {
            stringBuffer.append(charArray[i]);
        }
        String str = stringBuffer.toString();
        System.out.println(str); // cba
    }
  • 统计大串中小串出现的次数
package cn.king.demo01;

import org.junit.Test;

//统计maxString 中minString出现的次数
/*
 * 前提:知道了大串和小串
 * A:定义一个统计变量,初始化为0
 * B:先在大串中查找一次小串第一次出现的位置
 * 	    a:索引是-1,说明不存在,返回统计变量
 * 	    b:索引不是-1,说明存在,统计变量++
 * C:把刚才的索引+小串的长度作为开始截取上一次的大串,返回一个新的字符串,并把该字符串重新赋值给大串
 * B:回到B
 */
public class Demo08 {

    // 原始版
    @Test
    public void test01() {
        String maxString = "woaijavawoaijavawoaijava";
        String minString = "java";

        int count = 0;

        int index = maxString.indexOf(minString);

        while (index != -1) {
            count++;
            int startIndex = index + minString.length();
            maxString = maxString.substring(startIndex);
            index = maxString.indexOf(minString);
        }
        System.out.println(count);
    }

    // 优化版
    @Test
    public void test02() {
        String maxString = "woaijavawoaijavawoaijava";
        String minString = "java";

        int count = 0;

        int index;
        while ((index = maxString.indexOf(minString)) != -1) {
            count++;
            maxString = maxString.substring(index + minString.length());
            index = maxString.indexOf(minString);
        }
        System.out.println(count);
    }
    
}
  • 把字符串中的数字排序
package cn.king.demo01;
import org.junit.Test;
import java.util.Arrays;

/*
 * 我有如下一个字符串:"91 27 46 38 50"
 * 请写代码实现最终输出结果是:"27 38 46 50 91"
 *
 * 分析:
 * 		A:定义一个字符串
 * 		B:把字符串进行分割,得到一个字符串数组
 * 		C:把字符串数组变换成int数组
 * 		D:对int数组排序
 * 		E:把排序后的int数组在组装成一个字符串
 * 		F:输出字符串
 */
public class Demo09 {
    @Test
    public void test01() {
        // 定义一个字符串
        String str = "91 27 46 38 50";
        // 把字符串按照空格进行分割, 得到一个字符串数组
        String[] strArr = str.split(" ");
        // 把字符串数组转换成int数组
        int[] intArr = new int[strArr.length];
        for (int i = 0; i < intArr.length; i++) {
            intArr[i] = Integer.parseInt(strArr[i]);
        }
        // 对int数组进行排序
        Arrays.sort(intArr);
        // 把排序后的int数组再拼装成一个字符串
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < intArr.length; i++) {
            stringBuffer.append(intArr[i]).append(" ");
        }
        // 转换成字符串
        System.out.println(stringBuffer.toString());
    }
}

7. 基本数据类型转字符串的3三种方式

    @Test
    public void test01(){
        int i = 10086;

        // 基本数据类型转字符串的第一种方式 => 使用包装类的toString()方法
        Integer integer = Integer.valueOf(i);
        String s1 = integer.toString();

        // 基本数据类型转字符串的第二种方式 => 使用String类的valueOf()方法
        String s2 = String.valueOf(i);

        // 基本数据类型转字符串第第三种方式 => 使用空字符串拼接基本数据类型 
        String s3 = i + "";
    }

8. String相关面试题

8.1 String类能不能被继承,为什么?这种设计有什么好处?

  • String是final类型,final类不能被继承. Java之所以被设计成final类是有⼀定的考虑在的,主要在以下
    ⼏个⽅⾯。

  • 缓存Hashcode
    Java中经常会⽤到字符串的哈希码(hashcode)。例如,在HashMap中,字符串的不可变能保证其hashcode永远保持⼀致,这样就可以避免⼀些不必要的⿇烦。这也就意味着每次在使⽤⼀个字符串的hashcode的时候不⽤重新计算⼀次,这样更加⾼效。

  • 使其他类的使⽤更加便利
    在介绍这个内容之前,先看以下代码:

    HashSet<String> set = new HashSet<String>();
    set.add(new String("a"));
    set.add(new String("b"));
    set.add(new String("c"));
    for(String a: set)
        a.value = "a";
    

    在上面的例子中,如果字符串可以被改变,那么以上用法将有可能违反Set的设计原则,因为Set要求其中的元素不可以重复。上面的代码只是为了简单说明该问题,是伪代码,其实上面的代码也无法编译通过,String的value字段并无法从外部访问。

  • 安全性
    String被⼴泛的使⽤在其他Java类中充当参数。⽐如⽹络连接、打开⽂件等操作。如果字符串可变,那么类似操作可能导致安全问题。因为某个⽅法在调⽤连接操作的时候,他认为会连接到某台机器,但是实际上并没有(其他引⽤同⼀String对象的值修改会导致该连接中的字符串内容被修改)。可变的字符串也可能导致反射的安全问题,因为他的参数也是字符串。

  • 不可变对象天⽣就是线程安全的
    因为不可变对象不能被改变,所以他们可以⾃由地在多个线程
    之间共享。不需要任何同步处理。

  • 总之,String被设计成不可变的主要⽬的是为了安全和⾼效。所以,使String是⼀个不可变类是⼀个很好的设计。

8.2 String有没有长度限制,为什么?如果有,超过限制会发生什么?

  • String类有一个构造方法: public String(int[] codePoints,int offset,int count);
    可见理论上String的最大长度就是int的最大值: Integer.MAX_VALUE;
    但是实际上, String类的长度达不到这么长, 受堆内存和常量池的内存大小限制.

8.3 String的"+"是如何实现的?

    1. String s = “a” + “b”,编译器会进行常量折叠(因为两个都是编译期常量,编译期可知),即变成 String s = “ab”; 这就是常量优化机制. java会拿着"a"+“b"的结果"ab"到常量池中找, 如果有, 就引用这个"ab”, 如果没有, 就在常量池中创建一个"ab"对象再把该对象的地址值赋给String s.
    2. 对于能够进行优化的(String s = “a” + 变量 等)用 StringBuilder 的 append() 方法替代,最后调用 toString() 方法 (底层就是一个 new String())
/**
 问:String的“+”是如何实现的?
 
 1. String s = "a" + "b",
 编译器会进行常量折叠(因为两个都是编译期常量,编译期可知),即变成 String s = "ab"

 2. 对于能够进行优化的(String s = "a" + 变量 等)
 用 StringBuilder 的 append() 方法替代,
 最后调用 toString() 方法 (底层就是一个 new String())
 */
public class Demo02 {
    public static void main(String[] args) {
        /*
         * 对应反编译的代码:
         * String s1 = "ab";
         * String s2 = "b1";
         */
        String s1 = "a" + "b";
        String s2 = "b" + 1;

        /*
         * String s3 = (new StringBuilder()).append("a").append(s1).toString();
         */
        String s3 = "a" + s1;

        /*
         * String s4 = (new StringBuilder()).append("a").append(new Integer(1)).toString();
         */
        String s4 = "a" + new Integer(1);

        /*
         * String s5 = (new StringBuilder()).append(s2).append(s3).toString();
         */
        String s5 = s2 + s3;

        /*
         * String s6 = new String();
         * for (int i = 0; i < 2; i++) {
         *     s6 = (new StringBuilder()).append(s6).append(i).toString();
         *
         * }
         */
        String s6 = new String();
        for (int i = 0; i < 2; i++) {
            s6 += i;
        }

    }
}

9. StringBuffer类概述

详见另一篇博客: StringBuffer类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值