JavaSE(07) - API -String字符串

发布时间 2023-10-04 22:19:54作者: 大宝贝94106

JavaSE(07) - API -String字符串

p 96 API和API帮助文档

p97 String 概述

java.lang.String类代表字符串, java程序中的所有字符串文字(例如"abc")都是此类的对象.

注意点 : 字符串的内容是不会发生改变的, 他的对象在创建后不能被更改.

p89 String的构造方法代码实现和内存分析

常用构造方法

  1. 直接赋值 : String name = "George";
  2. new关键字
//1. 空参构造 : 可以获得一个空白的字符串对象.
String s1 = new String();//""
//2. 在参数中传递一个字符串
String s2 new String ("abc");//abc
//3. 传递一个字符数组, 根据数组的内容再创建一个新的字符串对象
//应用场景: 修改字符串的内容. abc -> Qbc
//"abc" --> {'a','b','c'} --> {'Q','b','c'} --> "Qbc"
char[] chars = {'a', 'b', 'c'};
        String s3 = new String(chars);
        System.out.println(s3);//abc
/*传递一个字节数组,根据字节数组的内容再创建一个新的字节串对象
 * 应用场景: 以后在网络当中传输信息其实都是字节信息,我们一般要把字节信息进行转换,转成字符串,就要用到这个构造.*/
        byte[] bytes = {97, 98, 99,100};
        String s4 = new String(bytes);
        System.out.println(s4);//abcd

String在java中的内存模型

1.直接赋值

String s = "abc";

当使用双引号直接赋值时, 系统会检查该字符串在串池(StringTable)中是否存在.

不存在 : 创建新的 存在 : 复用(不创建新的)

这种方式最常用, 代码简单, 节约内存.

2.使用new关键字

char [] chars = {'a','b','c'};
String s1 = new String(chars);
String s2 = new String(chars);

s1和s2不是一个字符串, 因为地址不同.

p99 字符串的比较

String s1 = "abc";//它是在串池中的数据
String s2 = "abc";//变量值一样,s2是复用s1的值
System.out.println(s1 == s2); //true
//-----------------------------
String s3 = new String("abc"); //记录堆里面的地址值
String s4 = "abc"; //记录串池中的地址值
System.out.println(s3 == s4); //false
  1. "==" 号 比较的原理 :

基本数据类型 : 比较的是具体的数据值

引用数据类型 : 比较的是地址值

  1. boolean equals 方法(要比较的字符串) 完全一样结果是true, 否则为false

boolean equalsIgnoreCase(要比较的字符串) 忽略大小写的比较

//1.创建两个字符串
        String s1 = new String("abc"); //小写
        String s2 = "ABC";  //大写
        //2.用==号比较
        /*基本数据类型 : 比较的是具体的数据值
          引用数据类型 : 比较的是地址值      */
        //地址值不一样
        System.out.println(s1 == s2);   //false
        //3.比较字符串中的内容是否相等
        boolean result1 = s1.equals(s2);    //区分大小写,必须完全一样
        System.out.println(result1);    //true
        boolean result2 = s1.equalsIgnoreCase(s2); //不区分大小写
        System.out.println(result2);    //false

只要是想比较字符串中的内容就必须用String类里的方法

p100 练习 - 用户登录

需求 : 已知正确的用户名和密码, 实现模拟用户登录. 共3次机会, 登录后, 给出相应提示.

 public static void logIn() {
        String rightUserName = "Qt";
        String rightPassword = "123";
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < 3; i++) {
            System.out.println("输入用户名:");
            String userName = scanner.next();
            System.out.println("输入密码:");
            String password = scanner.next();
            if (userName.equals(rightUserName) && password.equals(rightPassword)) {
                System.out.println("用户" + rightUserName + "登录成功.");
                return;
            } else {
                if (i == 2) {
                    System.out.println("用户" + rightUserName + "的账号被锁定,请与管理员联系.");
                } else System.out.println("登录失败,用户名或密码错误.还有" + (2 - i) + "次机会.");
            }
        }
    }

CTRL + Alt + T : 用各种结构包裹所选的代码(比如for,if...).

p101 练习 - 遍历字符串

需求 : 录入一个字符串, 实现在控制台遍历字符串.

  • public char charAt(int index) : 根据索引返回字符
  • public int length() : 返回此字符串长度
  • 数组的长度 : 数组名.length (属性:没有括号)
  • 字符串的长度 : 字符串对象.length() (方法:有括号)
  • 遍历字符串的for循环 : str.length().fori
 public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        System.out.println("输入一个字符串:");
        String str = s.next();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            System.out.println(c);
        }
    }

统计字符次数

练习 : 录入一个字符串, 统计当中的大写字母, 小写字母, 数字出现的次数(不考虑其它字符)

//1.需求 : 录入一个字符串, 实现在控制台遍历字符串.
//2.需求 : 录入一个字符串, 统计当中的大写字母, 小写字母, 数字出现的次数(不考虑其它字符)
public class printString_bigSmallNumber {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        System.out.println("输入一个字符串:");
        String str = s.next();
        countString(str);//调用方法
    }
    //遍历字符串方法
    public static void print_String(String str) {
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            System.out.println(c);
        }
    }
    //统计大小写数字方法
    public static void countString(String s){
        System.out.println("大写字母有" + big(s) + "个.");
        System.out.println("小写字母有" + small(s) + "个.");
        System.out.println("数字有" + number(s) + "个.");
    }
    //大写
    public static int big(String s) {
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c >= 'A' && c <= 'Z') {
                count++;
            }
        }
        return count;
    }
    //小写
    public static int small(String s) {
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c >= 'a' && c <= 'z') {
                count++;
            }
        }
        return count;
    }
    //数字
    public static int number(String s) {
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c >= '0' && c <= '9') {
                count++;
            }
        }
        return count;
    }
}

p102 练习 : 拼接字符串

需求 : 定义一个方法, 把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用方法, 并在控制台输出结果. 例如: int[]arr = {1,2,3} --> [1,2,3]

public class arrToString {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        String s = arrToStr(arr);
        System.out.println(s);
    }

    //拼接数组成字符串方法
    public static String arrToStr(int[] arr) {
        if (arr == null) {
            return "null";
        }
        if (arr.length == 0) {
            return "[0]";
        }
        String s = "[";
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                s = s + arr[i] + "]";
            } else {
                s = s + arr[i] + ", ";
            }
        }
        return s;
    }
}

字符串反转

练习 : 定义一个方法, 实现字符串反转, 录入一个字符串, 调用方法后, 控制台输出结果.例如, 录入abc, 输出cba

public class reverse {
    public static void main(String[] args) {
        String s = "123ABC";
        System.out.println(reverseString(s));
    }
    //反转字符串方法
    public static String reverseString(String s){
        String result = "";
        for (int i = s.length()-1; i >= 0; i--) {
            char c = s.charAt(i);
            result = result + c;
        }
        return result;
    }
}

小问题 :

  1. fori是从小到大++循环,forr是从大到小--循环

  2. 解决Idea中shift+F6快捷键失效问题
    在升级到windows11后,idea中的shift+F6不能使用了,感觉是热键冲突了。
    右键输入法,->常规 ->兼容性,使用以前版本的微软拼音输入法(开)

练习 - 金额转换

2135 --> 金额(大写) 零 佰 零 拾 零 万 贰 仟 壹 佰 叁 拾 伍 元 (总长度7位)
零0 壹1 贰2 叁3 肆4 伍5 陆6 柒7 捌8 玖9

{'零','壹','贰','叁','肆','伍','陆','柒','捌','玖'}

步骤 :

  1. 对输入的数据进行校验,(money)大于0, 小于等于9999999.
  2. 定义方法getCapitalNumber方法, 让数字和大写中文产生一一对应的关系. 定义String数组, 存储0~9的大写, 方法返回形参索引的元素.
  3. 获得money中的每一位数字, 在获取过程中调用getCapitalNumber方法, 反向拼接成字符串.
  4. 在获得的字符串中补0, 补到7位(7减去字符串长度).在字符串前面拼接0.
  5. 定义String数组存储单位, 遍历钱数字符串的同时把单位数组插入进去. 再把大写数字和单位拼接到一个字符串变量(result)中.
package API_String;

import java.util.Scanner;

/*p103 练习 - 金额转换
2135  -->  金额(大写) 零 佰  零 拾  零 万  贰 仟  壹 佰  叁 拾  伍 元 (总长度7位)
零   壹   贰   叁   肆   伍   陆   柒   捌   玖 {'零','壹','贰','叁','肆','伍','陆','柒','捌','玖'}
{'佰','拾','万','仟','佰','拾','元'}
步骤 :

1. 对输入的数据进行校验,(money)大于0, 小于等于9999999.
2. 定义方法getCapitalNumber方法, 让数字和大写中文产生一一对应的关系. 定义String数组, 存储0~9的大写, 方法返回形参索引的元素.
3. 获得money中的每一位数字, 在获取过程中调用getCapitalNumber方法, 反向拼接成字符串.
4. 在获得的字符串中补0, 补到7位(7减去字符串长度).在字符串前面拼接0.
5. 定义String数组存储单位, 遍历钱数字符串的同时把单位数组插入进去. 再把大写数字和单位拼接到一个字符串变量(result)中.*/
public class numberToCapital {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int money = 0;
        //对输入的数据进行校验
        while (true) {
            System.out.println("输入金额:");
            money = sc.nextInt();
            if (money > 0 && money <= 9999999) {
                break;
            } else System.out.println("金额无效,重新输入.");
        }
        //获得money中的每一位数字
        String s = "";
        while (money != 0) {
            int ge = money % 10;
            money /= 10;
            String capitalNumber = getCapitalNumber(ge);
            s = capitalNumber + s;

        }
        //在获得的字符串中补0
        int zero = 7 - s.length();
        for (int i = 0; i < zero; i++) {
            s = "零" + s;
        }
//        System.out.println(s);
        //插入单位
        String[] unit = {"佰", "拾", "万", "仟", "佰", "拾", "元"};
        String result = "";
        for (int i = 0; i < s.length(); i++) {
            result = result + s.charAt(i) + unit[i];
        }
        System.out.println(result);
    }
    //数字和大写中文转换方法
    public static String getCapitalNumber(int index) {
        String[] s = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        return s[index];
    }
}

p104 练习 手机号屏蔽(subString方法,截取字符串)

需求 : 录入手机号, 例如13812345678 转换成 138****5678 并输出.

package API_String;
/*手机号屏蔽
需求 : 录入手机号, 例如13812345678 转换成 138****5678 并输出.
*/
public class screenPhoneNumber {
    public static void main(String[] args) {
    String phoneNumber = "13812345678";
        String s = screenNumber(phoneNumber);
        System.out.println(s);
    }
    public static String screenNumber(String phomeNumber){
        //subString方法,截取头3位,和后4位
        String start = phomeNumber.substring(0, 3);
        String end = phomeNumber.substring(7);//从7到最后
        //拼接
        return start + "****" + end;
    }
}

身份证号码信息查看

需求 : 录入身份证号码, 例如1122198603191121 打印 此人信息为:出生日期: XXXX年X月X日 性别为: 男/女

/*身份证信息 1,2位:省份. 3,4位:城市. 5,6位:区县. 7-14位:出生年月日. 15,16位:所在地派出所. 17位性别(奇数男性,偶数女性). 18位:个人信息码(随机生成)*/
package API_String;

/*身份证号码信息查看
需求 : 录入身份证号码, 例如210106198603191121 打印 此人信息为:出生日期: XXXX年X月X日	性别为: 男/女*/
public class IDMassage {
    public static void main(String[] args) {
        String IDNumber = "111111199006291220";
        getMassage(IDNumber);
    }
    public static void getMassage(String IDNumber) {
        //截取有用的部分
        String year = IDNumber.substring(6, 10);
        String month = IDNumber.substring(10, 12);
        String day = IDNumber.substring(12, 14);
        char gender = IDNumber.charAt(16);
        //输出信息
        System.out.println("此人信息位" + "出生日期: " + year + "年" + month + "月" + day + "日");
        //判断性别  '字符' - 48 把字符所对应的数字和48('0')相减(差值)
        if ((gender - 48) % 2 == 0) {
            System.out.println("性别:女");
        } else System.out.println("性别:男");
    }
}

游戏骂人敏感词替换

需求 : 把字符串中的特定词替换成(replace方法)$, 例如"你tmd是sb啊." -> "你$$$是$$$啊."

public class replaceWords {
    public static void main(String[] args) {
        String dialog = "你tmd是sb啊.";
        String s = replaceW(dialog);
        System.out.println(s);
    }
    //敏感词替换方法 , replace
    public static String replaceW(String s) {
        //定义词库
        String [] words = {"sb","tmd","nmb","cnm"};
        //循环词库数组,把s(形参字符串)中如果有词库中的词,都替换成***
        for (int i = 0; i < words.length; i++) {
            s = s.replace(words[i],"$$$");
        }
        return s;
    }
}

p105 StringBuilder的基本操作

构造方法 :

  1. 空参构造 创建一个空白的可变字符串对象
  2. String 类型参数 根据字符串的内容, 创建可变字符串对象

成员方法 :

  1. append(任意类型) 添加数据, 返回对象本身
  2. reverse() 反转容器中的内容
  3. length() 返回长度
  4. toString() StringBuilder转换位String

打印StringBuilder时是属性值而不是地址值

p105 练习 - 对称字符串

需求 : 录入一个字符串, 程序判断是否是对称字符串.例如:对称字符串: 12321 , 111; 非对称字符串: 123

public class StringBuilderExercise_1 {
    public static void main(String[] args) {
        System.out.println(isReturnString());
    }
    public static boolean isReturnString(){
        Scanner sc = new Scanner(System.in);
        System.out.println("输入一个字符串:");
        String s = sc.next();
        String sb = new StringBuilder(s).reverse().toString();
        return s.equals(sb);
    }
}

练习 - 数组转字符串

需求: 定义一个方法, 把int 数组中的数据按照指定格式拼接成一个字符串返回.
例如: 数组位int[] arr = {1,2,3} 输出结果 : [1, 2, 3]

public class StringBuilderExercise_2 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        System.out.println(arrayToString(arr));
    }
    public static String arrayToString(int[] arr) {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                sb.append(arr[i]).append("]");
            } else
                sb.append(arr[i]).append(", ");
        }
        return sb.toString();
    }
}

使用StringBuilder的场景 : 1. 字符串的拼接. 2. 字符串的反转.

p106 StringJoiner

概述

  • 跟StringBuilder一样, 也是一个容器, 创建后里面的内容是可变的.
  • 作用: 提高字符串的操作效率, 编码简洁.
  • JDK8出现的

构造方法

StringJoiner(间隔符号) 如("--") 1--2--3

StringJoiner(间隔符号, 开始符号, 结束符号) (", "[","]") [1, 2, 3]

成员方法

  • add(添加的内容) 添加数据, 返回对象本身
  • length() 返回长度
  • toString() 返回一个字符串(拼接的结果)
public class StringJoinerDemo {
    public static void main(String[] args) {//
        StringJoiner sj = new StringJoiner(", ","[","]");
        String s = sj.add("a").add("b").add("c").add("d").toString();
        System.out.println(s);
    }
}       //  [a, b, c, d]

字符串-总结

  1. String - 字符串类, 定义了很多操作字符串的方法
  2. StringBuilder - 可变容器, 可以高效的拼接/反转字符串
  3. StringJoiner - JDK8出现, 可以高效,方便的拼接字符串.

p107 字符串相关的底层原理

CTRL+F12 在类中查找方法

字符串拼接时有变量参与: 在内存中创建了很多对象, 浪费空间, 时间也非常慢.

所以如果很多字符串变量拼接, 不要直接 "+" . 在底层会创建多个对象, 浪费时间,浪费性能.

问题: 下列代码的运行结果是?

public class StringsCompare {
    public static void main(String[] args) {
        String s1 = "abc";//记录串池中的地址值
        String s2 = "ab";
        String s3 = s2 + "c";//底层在堆中new StringBuilder对象来拼接
        System.out.println(s1 == s3);
    }
}		//false

问题: 下列代码的运行结果是?

String s1 = "abc";//记录串池中的地址值
        String s2 = "a"+"b"+"c";//没有变量参与,复用串池中的字符串
        System.out.println(s1 == s2);
//true

字符串原理小结
扩展底层原理1: 字符串存储的内存原理

  • 直接赋值会复用字符串常置池中的
  • new出来不会复用,而是开辟一个新的空间

扩展底层原理2: ==号比较的到底是什么?

  • 基本数据类型比较数据值
  • 引用数据类型比较地址值

扩展底层原理3: 字符串拼接的底层原理

  • 如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用串池中的字符串。
  • 如果有变量参与,会创建新的字符串,浪费内存。

扩展底层原理4: StringBuilder提高效率原理

  • 所有要拼接的内容都会往StringBuelder中放, 不会创建很多无用的空间, 节约内存

扩展底层原理5: StringBuilder原码分析

  • 默认创建一个长度为16的字节数组
  • 添加的内容长度小于16,直接存
  • 添加的内容大于16会扩容(原来的容量*2+2)
  • 如果扩容之后还不够,以实际长度为准

p108 练习 - 罗马数字

需求: 录入一个字符串. 要求1:长度小于等于9. 要求2:只能有数字. 将内容变成罗马数字
阿拉伯数字和罗马数字对比关系
I - 1, II - 2, III - 3, IV - 4, V - 5, VI - 6, VII - 7, 8 - VIII ,9 - IX - 9
注意点: 罗马数字里面没有0, 如果键盘录入数字包含0, 可以变成 "",(长度为0的字符串)


p109 练习 - 字符串旋转

需求: 给定两个字符串, A 和 B. A的旋转操作就是将A最左边的字符移动到最右边. 例如,A = "abcde", 在移动一次之后结果就是"bcdea". 如果在若干次调整操作之后, A 能变成 B, 那么返回True.如果不能匹配成功, 则返回false