JavaSE基础(十二) - String 👾

String 字符串.png

今天学习了 Java 字符串的常用操作,写出来和简友们分享一下☺️
还是老规矩,先上思维导图。

1.String 概述

一起读 API 📖
public final class String extends Object
implements Serializable, Comparable<String>, CharSequence
The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class.

通过查看 API 的概述我们可以知道以下几点:

  • String 是一个 final 修饰的类,不能被继承。
  • 字符串字面量值 "abc"也可以被看做是 String 对象。
字符内存图1

Reminder💁‍♂️:常量池中的值是不可被改变,但 String 对象是可以重指向的。


2.String 构造方法

  • public String()
    空构造。

  • public String(byte[] bytes)
    字节数组 -> 字符串(使用平台默认字符集解码)

一起读 API 📖
Constructs a new String by decoding the specified array of bytes using the platform's default charset.

  • public String(byte bytes[], int offset, int length)
    将 byte 数组 从 offset 开始 转换 length 个。

  • public String(char value[])
    char 数组转换成字符串。

  • public String(char value[], int offset, int count)
    从数组中第 offset 开始转换,转换 count 个 char 为字符串。

  • public String(String original)
    将字符串常量 -> 字符串对象。


3.String 面试题

  • 判断两个字符串地址值是否相等
    str1 和 str2 都存储在常量池,如果常量池中没有这个字符串对象,就创建一个,如果有就直接用;因为常量池中已经存在了 “abc”,所以 str2 直接使用,str1 与 str2指向了同一个对象,而 == 运算符比较的是两个对象的地址值,因此 str1 == str2。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);   // true
System.out.println(str1.equals(str2));  // true
字符串内存图2
  • 下面这句话在内存中创建了几个对象?
    这段代码创建了两个对象,"abc" 存储在常量池中,new 的对象是存在堆内存中。
String str1 = new String("abc");

一起读 API 📖
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.

  • 判断定义为 String 类型的 str1 和 str2 是否相等?
    str1:指向堆内存对象的地址值。
    str2:指向常量池中的地址值。
String str1 = new String(“abc”);
String str2 = “abc”;
System.out.println(str1 == str2);           // false
System.out.println(str1.equals(str2));  // true
  • 判断定义为 String 类型的 str1 和 str2 是否相等?
    Java 中有常量优化机制,在编译时就将 str2 转换成了 “abc”,所以两个变量指向同一个常量池,内存地址值相同。
String str1 = "a" + "b" + "c";
String str2 = "abc";
System.out.println(str1 == str2);           // true
System.out.println(str1.equals(str2));  // true
  • 判断定义为 String 类型的 str2 和 str3 是否相等?
    字符串中 + 操作是通过 StringBuilderStringBuffer 以及 append 方法实现的,字符串转换是通过 toString 方法实现的。在堆内存和常量池中的地址都不同。
String str1 = "ab";
String str2 = "abc";
String str3 = str1 + "c";
System.out.println(str2 == str3);           // false
System.out.println(str2.equals(str3));  // true
字符串内存图3

一起读 API 📖
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java.


4.String 判断方法

  • public boolean equals(Object anObject)
    判断字符串是否相等。

Reminder💁‍♂️:比较是会判断大小写的。

  • public boolean equalsIgnoreCase(String anotherString)
    忽略大小写,判断字符串是否相等。

  • boolean constans(String str)
    判断大字符串中是否包含小字符串。

  • boolean startsWith(String str)
    判断字符串中是否以某个指定的字符串开头。

  • boolean endsWith(String str)
    判断字符串中是否以某个指定的字符串结尾。

  • boolean isEmpty()
    判断字符串是否为空。

Reminder💁‍♂️:如果 String == null 调用该方法会出现空指针异常


5.Test👨‍💻模拟登录功能

  • 模拟登录:

    1. 用户每日有三次机会,如果输入错误,提示还剩几次。
    2. 用户名和密码都是 admin。
public class String_Test1 {

    private static Scanner sc = new Scanner(System.in);

    private static final String USER_NAME = "admin";

    private static final String PASSWORD = "admin";

    private static final int CHANCE_TIMES = 3;

    public static void test() {
        for (int i = 0; i < CHANCE_TIMES; i++) {
            System.out.print("Please enter user name: ");
            String userName = sc.nextLine();
            System.out.print("Please enter password: ");
            String password = sc.nextLine();
            // 用字符串常量去做比较,防止字符串变量为 null。
            if (USER_NAME.equals(userName) && PASSWORD.equals(password)) {
                System.out.println("Welcome " + userName + " login.");
                break;
            } else {
                // 今日试错次数用完,则给出提示。
                if (i == CHANCE_TIMES - 1) {
                    System.out.println("Today chance use up, please tomorrow login.");
                    break;
                }
                // 给出错误提示,并输出今日剩余试错次数。
                System.out.println("LoginFail: userName or password error.");
                System.out.println("You has " + (CHANCE_TIMES - 1 - i) + " times.");
            }
        }
    }
}

6.String 获取方法

  • int length()
    获取字符串长度方法。

Reminder💁‍♂️:我们的中文占 1 字符,转译符也占 1 字符。

  • char charAt(int index)
    获取指定索引位置的字符。

Reminder💁‍♂️:StringIndexOutOfBoundsException 字符串索引越界异常

  • int indexOf(int ch)
    返回指定字符在字符串中第一次出现的索引

Reminder💁‍♂️:
可以传递 char 类型参数,因为会自动类型提升为 int
如果不存在则返回 -1

  • int indexOf(String str)
    返回指定 字符串 在字符串中第一个字符出现的索引。

Reminder💁‍♂️:
如果不存在则返回 -1

  • int indexOf(int ch, int fromIndex)
    返回指定字符在此字符串中从指定索引开始第一次出现处的索引。

Reminder💁‍♂️:包括当前索引 [fromIndex, ...]

  • int lastIndexOf(int ch, int fromIndex)
    从指定位置开始向前查找,返回第一次出现的索引

  • String substring(int start)
    从指定位置开始截取字符串,默认截取到末尾

  • String substring(int start, int end)
    返回字符串,从指定位置开始到指定位置结束截取字符串。

Reminder💁‍♂️:[start, end) 左闭右开。


7.String 遍历

// 方式一
String str = "Sawyer";
for (int i = 0; i < str.length(); i++) {
    char ch = str.charAt(i);
    System.out.println(ch);
}
// 方式二
char[] arr_char = str.toCharArray();
    for (int i = 0; i < arr_char.length; i++) {
    System.out.println(arr_char[i]);
}

8.Test👨‍💻统计不同字符类型的个数

  • 题目要求:统计一个字符串中(大写字母、小写字母、数字、其他字符)出现次数,其他字符出现次数。
  • 测试数据:ABCDEabcd123456!@#$%
public static void test() {

    String str = "ABCDEabcd123456!@#$%";

    int lowerCaseCount = 0;
    int upperCaseCount = 0;
    int numberCount = 0;
    int otherCount = 0;

    for (int i = 0; i < str.length(); i++) {
        // String -> char[] 进行遍历
        char ch = str.charAt(i);
        if (ch >= 'a' && ch <= 'z') {
            lowerCaseCount++;
        } else if (ch >= 'A' && ch <= 'Z') {
            upperCaseCount++;
        } else if (ch >= '0' && ch <= '9') {
            numberCount++;
        } else {
            otherCount++;
        }
    }

    System.out.println("lowerCaseCount = " + lowerCaseCount + ", upperCaseCount = "
            + upperCaseCount + ", numberCount = " + numberCount +
            ", otherCount = " + otherCount + ".");
}

9.String 转换方法

  • public byte[] getBytes()
    通过 GBK 码表将字符串转换为字节数组。

Reminder💁‍♂️:
GBK 码表一个中文占用两个字节
中文的第一个字节是负数

  • public char[] toCharArray()
    将字符串转换为字符数组。

  • static String valueOf(char[] chs)
    将字符串转换为字符数组。

  • public static String valueOf(int i)
    将 int 类型转换为字符串。

Reminder💁‍♂️:
通过重载方法,可以将任意类型转换为字符串。
静态方法,底层是由 String 类的构造方法完成的。

  • public String toLowerCase()
    字符串小写转换,返回字符串

  • public String toUpperCase()
    字符串大写转换,返回字符串。

  • public String concat(String str)
    字符串拼接,返回字符串。

Reminder💁‍♂️:
concat :只能对两个 String 做拼接操作。
+ :使用的更广泛。


10.String 其他方法

  • public String replace(char oldChar, char newChar)
    字符替换。

Reminder💁‍♂️:如果 oldChar 不存在,则保留原字符不改变。

  • public String replace(CharSequence target, CharSequence replacement)
    字符串替换。

  • public String trim()
    去除字符串两侧的空格,返回新字符串。

  • public int compareTo(String anotherString)
    按字符逐个比较两个字符串 unicode 码表值,如果长度相等,只返回第一个不同字符 unicode 对应的差值;如果长度不等则 length 相减。

String str1 = "abc";
String str2 = "abcd";
int str_compare = str1.compareTo(str2);
System.out.println(str_compare);        // -1

11.Test👨‍💻String关键字检索

  • 题目要求:
    1.在 source 字符串中检索 target 关键字出现的次数。
    2.将 target 关键字在字符串中用 "[ ]" 标记。
public class String_Test8 {

    public static void test() {
        String source = "woailuchen,luchenbutongyuyaoyanhuo," +
                "wulunluchenhaishiyaoyanhuo,liaodelaidejiushihaobaobao";
        String target = "luchen";

        int count = targetCount(source, target);
        System.out.println(count);
        String mark_str = markStringAccordingTraget(source, target);
        System.out.println(mark_str);
    }

    // 获取检索关键字出现次数
    private static int targetCount(String source, String target) {
        int targetCount = 0;
        {
            // 从targetOffset关键字处开始检索
            int targetOffset = 0;
            while (true) {
                int targetIndex = source.indexOf(target, targetOffset);
                if (targetIndex == -1) {
                    break;
                } else {
                    // 改变将检索开始的fromindex
                    targetOffset = targetIndex + target.length();
                    targetCount++;
                }
            }
        }
        return targetCount;
    }

    // 将关键字用 "[]" 标记
    private static String markStringAccordingTraget(String source, String target) {
        return source.replace(target, " [ " + target + " ] " +
                "");
    }
}

悄悄话 🌈

  • 这是我个人发表的第 3 篇简书 Blog,靠着大家的鼓励我会继续抽时间继续和大家分享我在 JavaSE 的学习中的一点心得,也希望读者们多多批评指教,多多支持。
  • 每篇文章最开心的地方就是在这里和大家分享一点我个人最近的情况,最近每天都睡的很晚,大概每天保持 5 小时的睡眠的样子,因为明天放假一天,所以抽时间写了这篇总结。
  • 之前做 iOS 开发,来简书中每次都能找到满意的答案,也看了很多大牛们,不光是技术能力强,技术的表述能力也是一流。现在轮到我自己从 Java 小白开始学习了,我知道也许会有很多人在现阶段和我一样需要有人帮助解答问题,我认为我除了自己的学习总结之外还可以做的更多,每次收到文章的点赞我都深深的感觉到自己做了一件很有意义的事情。
  • 后面的学习可能需要用到更多的代码示例,在文章中引用代码块的方式可能不太合适了,我会将项目放在 GitHub 上,并且在文章中附上链接,小伙伴们到时要记得光顾哟!🤡

彩蛋 🐣

  • 最近开通了简书专题 JavaSE 成长之路,主要为一样正在 JavaSE 修行中的简友们提供了技术交流的平台,希望大家多多投稿交流互动。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容