初识java(十五):字符串-String类

目录

一:String类的重要性

二:String原理介绍

1.字符串构造

2.字符串常量池(StringTable)

3.字符串内存存储

三:常⽤⽅法介绍

1.String对象的⽐较

1.==⽐较是否引⽤同⼀个对象

[2.equals ⽅法:按照字典序⽐较](#2.equals ⽅法:按照字典序⽐较)

[3.compareTo ⽅法:按照字典序进⾏⽐较](#3.compareTo ⽅法:按照字典序进⾏⽐较)

[4.compareToIgnoreCase ⽅法:与compareTo⽅式相同,但是忽略⼤⼩写⽐较](#4.compareToIgnoreCase ⽅法:与compareTo⽅式相同,但是忽略⼤⼩写⽐较)

2.字符串查找

3.转换

1.数字和字符串转化

2.⼤⼩写转换

3.字符串转数组

4.格式化

4.字符串的替换

5.字符串的拆分

6.字符串截取

7.去除左右两边的空格

8.intern⽅法

四:字符串的不可变性

五:字符串修改

1.StringBuilder的介绍

2.StringBuffer的介绍


内容大纲:

本文介绍了Java中String类的重要性和基本原理。String类解决了C语言字符串操作的不足,采用面向对象方式封装字符串功能。文章详细讲解了String的构造方法、字符串常量池机制、内存存储方式,以及常用操作方法(比较、查找、转换、替换、拆分等)。同时阐述了String的不可变性特点,并推荐使用StringBuilder和StringBuffer进行高效字符串修改。最后对比了StringBuffer(线程安全)和StringBuilder(非线程安全)的差异,提供了完整的字符串处理解决方案。

一:String类的重要性

在C语⾔中已经涉及到字符串了,但是在C语⾔中要表⽰字符串只能使⽤字符数组或者字符指针,可以 使⽤标准库提供的字符串系列函数完成⼤部分操作,但是这种将数据和操作数据⽅法分离开的⽅式不 符合⾯向对象的思想,⽽字符串应⽤⼜⾮常⼴泛,因此Java语⾔专⻔提供了String类。

二:String原理介绍

1.字符串构造

String类提供的构造⽅式⾮常多,常⽤的就以下三种:

java 复制代码
public class Test {
    public static void main(String[] args) {
        //使⽤字符串常量进⾏赋值
        String s1 = "hello";
        System.out.println(s1);

        //直接new String对象
        String s2= new String("hello ");
        System.out.println(s2);

        //使⽤字符数组进⾏构造
        char[] arry = {'h','e','l','l','o'};
        String s3 = new String(arry);

        //使⽤字节数组构造对象
        byte[] bytes = {91,92,93,94};
        String s4 = new String(bytes);
        System.out.println(s4);
    }
}

输出:

其他构造⽅法需要⽤到时,⼤家参考Java在线⽂档:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html

查看String源码,我们观察到:String是引⽤类型,内部并不存储字符串本⾝。

2.字符串常量池(StringTable)

想要了解字符串的布局,我们⾸先得了解⼀个新的内存叫做:字符串常量池(StringTable).

字符串常量池在JVM中是String Table类,实际是⼀个固定⼤⼩的HashTable(⼀种⾼效⽤来进⾏查找的数据结构,后续给⼤家详细介绍),不同JDK版本下字符串常量池的位置以及默认⼤⼩是不同的:

关于⽅法区、堆等内存结构的具体局部,后续JVM中会给⼤家详细介绍。

关于"池"的理解:

"池"是编程中的⼀种常⻅的,重要的提升效率的⽅式,我们会在未来的学习中遇到各种"内存池","线 程池","数据库连接池"....

⽐如:家⾥给⼤家打⽣活费的⽅式

1.家⾥经济拮据,每⽉定时打⽣活费,有时可能会晚,最差情况下可能需要向家⾥张⼝要,速度慢

2.家⾥有矿,⼀次性打⼀年的⽣活费放到银⾏卡中,⾃⼰随⽤随取,速度⾮常快

⽅式2,就是池化技术的⼀种⽰例,钱放在卡上,随⽤随取,效率⾮常⾼。常⻅的池化技术⽐如:数 据库连接池、线程池等。

3.字符串内存存储

java 复制代码
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abc";
        System.out.println(s1==s2);
    }

说明:

1.s1在进⾏存储的时候,"abc"会先存储到字符串常量池当中

2.当s2再次存储的时候,先会检查字符串常量池当中是否存在"abc"常量,如果存在,则不再重复 存储

java 复制代码
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 =new String("abc");
        System.out.println(s1==s2);
    }

说明:

1.第⼀次存储的时候,会将"abc"存储到常量池当中

2.每次new都会在堆中实例化新的对象

3.存储s2的时候,会使⽤常量池的"abc"对象进⾏存储

三:常⽤⽅法介绍

1.String对象的⽐较

字符串的⽐较是常⻅操作之⼀,⽐如:当你登录⼀个⽹站的时候,输⼊了⽤⼾名和密码之后,需要后 台进⾏⽐较和对⽐。

1.==⽐较是否引⽤同⼀个对象

注意:对于内置类型,==⽐较的是变量中的值;对于引⽤类型==⽐较的是引⽤中的地址。

java 复制代码
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int c = 10;

        //对于基本类型变量,==⽐较两个变量中存储的值是否相同
        System.out.println(a==c);
        System.out.println(a==b);

        //对于引⽤类型变量,==/⽐较两个引⽤变量引⽤的是否为同⼀个对象
        String s1=new String("hello");
        String s2=new String("world");
        String s3=new String("hello");
        String s4=s1;

        System.out.println(s1==s2);
        System.out.println(s1==s3);
        System.out.println(s1==s4);
    }

输出:

2.equals ⽅法:按照字典序⽐较

字典序:字符⼤⼩的顺序

String类重写了⽗类Object中equals⽅法,Object中equals默认按照==⽐较,String重写equals⽅法 后,按照如下规则进⾏⽐较,⽐如: s1.equals(s2)

JDK17当中的源码部分:

使用:

java 复制代码
    public static void main(String[] args) {
        String s1=new String("hello");
        String s2=new String("hello");
        String s3=new String("ccccc");

        System.out.println(s1==s2);
        System.out.println(s1==s3);

        System.out.println(s1.equals(s2));
        System.out.println(s1.equals(s3));
    }

输出:

3.compareTo ⽅法:按照字典序进⾏⽐较

与equals不同的是,equals返回的是boolean类型,⽽compareTo返回的是int类型。具体⽐较⽅式:

  1. 先按照字典次序⼤⼩⽐较,如果出现不等的字符,直接返回这两个字符的⼤⼩差值

  2. 如果前k个字符相等(k为两个字符⻓度最⼩值),返回值两个字符串⻓度差值

java 复制代码
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("abc");
        String s4 = new String("abcdef");
        System.out.println(s1.compareTo(s2));   //不同输出字符差值-1
        System.out.println(s1.compareTo(s3));   //相同输出0
        System.out.println(s1.compareTo(s4)); //前k个字符完全相同,输出⻓度差值-3
    }

输出:

4.compareToIgnoreCase ⽅法:与compareTo⽅式相同,但是忽略⼤⼩写⽐较

java 复制代码
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("abc");
        String s4 = new String("abcdef");
        System.out.println(s1.compareToIgnoreCase(s2));   
        System.out.println(s1.compareToIgnoreCase(s3));
        System.out.println(s1.compareToIgnoreCase(s4));
    }

输出:

2.字符串查找

字符串查找也是字符串中⾮常常⻅的操作,String类提供的常⽤查找的⽅法:

方法 功能
char charAt(int index) 返回 index 位置上字符,如果 index 为负数或者越界,抛出 IndexOutOfBoundsException 异常
int indexOf(int ch) 返回 ch 第一次出现的位置,没有返回 -1
int indexOf(int ch, int fromIndex) 从 fromIndex 位置开始找 ch 第一次出现的位置,没有返回 -1
int indexOf(String str) 返回 str 第一次出现的位置,没有返回 -1
int indexOf(String str, int fromIndex) 从 fromIndex 位置开始找 str 第一次出现的位置,没有返回 -1
int lastIndexOf(int ch) 从后往前找,返回 ch 第一次出现的位置,没有返回 -1
int lastIndexOf(int ch, int fromIndex) 从 fromIndex 位置开始找,从后往前找 ch 第一次出现的位置,没有返回 -1
int lastIndexOf(String str) 从后往前找,返回 str 第一次出现的位置,没有返回 -1
int lastIndexOf(String str, int fromIndex) 从 fromIndex 位置开始找,从后往前找 str 第一次出现的位置,没有返回 -1

代码:

java 复制代码
public class StringSearchExample {
    public static void main(String[] args) {
        // 定义一个测试字符串,方便观察索引位置
        // 索引: 0123456789...
        String text = "Hello World, Hello Java";
        System.out.println("测试字符串: \"" + text + "\"");
        System.out.println("-----------------------------------");

        // 1. char charAt(int index)
        // 功能:返回指定索引处的字符
        char c = text.charAt(1);
        System.out.println("1. charAt(1): " + c); // 输出 'e'

        // 2. int indexOf(int ch)
        // 功能:返回指定字符第一次出现的索引
        int idx1 = text.indexOf('o');
        System.out.println("2. indexOf('o'): " + idx1); // 输出 4 (World中的o)

        // 3. int indexOf(int ch, int fromIndex)
        // 功能:从指定索引开始,返回字符第一次出现的索引
        int idx2 = text.indexOf('o', 5);
        System.out.println("3. indexOf('o', 5): " + idx2); // 输出 7 (Java前的o,跳过了第一个)

        // 4. int indexOf(String str)
        // 功能:返回指定子字符串第一次出现的索引
        int idx3 = text.indexOf("Hello");
        System.out.println("4. indexOf(\"Hello\"): " + idx3); // 输出 0

        // 5. int indexOf(String str, int fromIndex)
        // 功能:从指定索引开始,返回子字符串第一次出现的索引
        int idx4 = text.indexOf("Hello", 1);
        System.out.println("5. indexOf(\"Hello\", 1): " + idx4); // 输出 13 (第二个Hello)

        // 6. int lastIndexOf(int ch)
        // 功能:返回指定字符最后一次出现的索引(从后往前找)
        int idx5 = text.lastIndexOf('l');
        System.out.println("6. lastIndexOf('l'): " + idx5); // 输出 22 (Java中的l)

        // 7. int lastIndexOf(int ch, int fromIndex)
        // 功能:从指定索引开始向前搜索,返回字符最后一次出现的索引
        int idx6 = text.lastIndexOf('l', 10);
        System.out.println("7. lastIndexOf('l', 10): " + idx6); // 输出 3 (Hello中的第二个l,因为限制了范围在10以内)

        // 8. int lastIndexOf(String str)
        // 功能:返回指定子字符串最后一次出现的索引
        int idx7 = text.lastIndexOf("Hello");
        System.out.println("8. lastIndexOf(\"Hello\"): " + idx7); // 输出 13

        // 9. int lastIndexOf(String str, int fromIndex)
        // 功能:从指定索引开始向前搜索,返回子字符串最后一次出现的索引
        int idx8 = text.lastIndexOf("Hello", 12);
        System.out.println("9. lastIndexOf(\"Hello\", 12): " + idx8); // 输出 0 (因为在索引12之前只有一个Hello)

        // 补充:未找到时的返回值
        System.out.println("-----------------------------------");
        System.out.println("indexOf('z'): " + text.indexOf('z')); // 输出 -1
    }
}

3.转换

1.数字和字符串转化

java 复制代码
class NumberStringConvert {
    public static void main(String[] args) {

        // ================= 1. 数字转字符串 =================
        System.out.println("========== 数字转字符串 ==========");

        int num = 12345;
        double pi = 3.14159;

        // 方法一:使用 String.valueOf() 【最推荐,通用且安全】
        String str1 = String.valueOf(num);
        System.out.println("1. String.valueOf(num): " + str1);

        // 方法二:使用包装类的 toString() 方法
        String str2 = Integer.toString(num);
        String str3 = Double.toString(pi);
        System.out.println("2. Integer.toString(num): " + str2);
        System.out.println("   Double.toString(pi): " + str3);
        
        // ================= 2. 字符串转数字 =================
        System.out.println("\n========== 字符串转数字 ==========");

        String intStr = "67890";
        String doubleStr = "98.76";

        // 方法一:使用包装类的 parseXxx() 方法 【最常用,返回基本数据类型】
        int parsedInt = Integer.parseInt(intStr);
        double parsedDouble = Double.parseDouble(doubleStr);
        System.out.println("1. parseInt / parseDouble 结果: " + (parsedInt + 1) + ", " + (parsedDouble + 1));

        // 方法二:使用包装类的 valueOf() 方法 (返回包装类对象,如 Integer, Double)
        Integer intObj = Integer.valueOf(intStr);
        System.out.println("2. Integer.valueOf 结果: " + (intObj + 1));

    }
}

输出:

2.⼤⼩写转换

java 复制代码
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "HELLO";
        //⼩写转⼤写
        System.out.println(s1.toUpperCase());
        //大写转小写
        System.out.println(s2.toLowerCase());
    }

输出:

3.字符串转数组

java 复制代码
    public static void main(String[] args) {
        // ================= 1. 字符串转数组 =================
        String word = "Hello";
        char[] chars = word.toCharArray();
        System.out.println("转为数组: " + Arrays.toString(chars));

        // ================= 2. 数组转字符串 =================
        String[] names = {"张三", "李四", "王五"};
        String joinedStr2 = Arrays.toString(names);
        System.out.println("转为字符串: " + joinedStr2);
    }

输出:

4.格式化

java 复制代码
    public static void main(String[] args) {
        String word = "Hello";
        String s = String.format("%d-%d-%d", 2019, 9,14);
        System.out.println(s);
    }

输出:

4.字符串的替换

使⽤⼀个指定的新的字符串替换掉已有的字符串数据,可⽤的⽅法如下:

java 复制代码
    public static void main(String[] args) {
        String str = "helloworld" ;
        System.out.println(str.replaceAll("l", "_"));
        System.out.println(str.replaceFirst("l", "_"));
    }

输出:

5.字符串的拆分

可以将⼀个完整的字符串按照指定的分隔符划分为若⼲个⼦字符串。

可⽤⽅法如下:

实现字符串的拆分处理

java 复制代码
    public static void main(String[] args) {
        String str = "hello world hello bit" ;
        String[] result = str.split(" ") ; //按照空格拆分

        for(String s: result) {
            System.out.println(s);
        }
    }

输出:

字符串的部分拆分(把内容分成多少份)

java 复制代码
    public static void main(String[] args) {
        String str = "hello world hello bit" ;
        String[] result = str.split(" ",2) ;
        for(String s: result) {
            System.out.println(s);
        }
    }

输出:

拆分是特别常⽤的操作.⼀定要重点掌握.另外有些特殊字符作为分割符可能⽆法正确切分,需要加上转 义.

6.字符串截取

从⼀个完整的字符串之中截取出部分内容。可⽤⽅法如下:

java 复制代码
    public static void main(String[] args) {
        String str = "helloworld" ;
        System.out.println(str.substring(5));
        System.out.println(str.substring(0, 5));
    }

输出:

注意事项:

1. 索引从0开始

2. 注意前闭后开区间的写法,substring[0,5)表⽰包含0号下标的字符,不包含5号下标

7.去除左右两边的空格

java 复制代码
    public static void main(String[] args) {
        String str = "   hello  world   " ;
        System.out.println("["+str+"]");
        System.out.println("["+str.trim()+"]");
    }

输出:

8.intern⽅法

当调⽤ intern() ⽅法时,如果字符串常量池中已经包含⼀个等于此String对象的字符串(由 equals(Object)⽅法确定),则返回常量池中的字符串。

否则,将此String对象添加到常量池中,并返回此String对象的引⽤。

java 复制代码
    public static void main(String[] args) {
        char[] ch = new char[]{'a', 'b', 'c'};
        String s1 = new String(ch); // s1对象并不在常量池中
        s1.intern();
        String s2 = "abc"; //"abc"在常量池中存在
        System.out.println(s1 == s2);
    }

输出:

注意:

1.如果不加s1.intern(); 输出的值是false

2.如果加了,则输出true

四:字符串的不可变性

String是⼀种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:

1. String类在设计时就是不可改变的,String类实现描述中已经说明了

2. 所有涉及到可能修改字符串内容的操作都是创建⼀个新对象,改变的是新对象

3. String之所以不可以被修改的原因是内部数组因为为私有成员

五:字符串修改

对于String类本⾝来说,是不可以修改的。形如如下代码:

java 复制代码
    public static void main(String[] args) {
        String s = "hello";
        s = s + " world";
        System.out.println(s);
    }

输出:

在这个例⼦中, s + " world" 创建了⼀个新的String对象,⽽原来的"Hello"对象保持不变.对于 String的拼接来说,如果是在循环当中会产⽣很多的临时对象。此时Java提供了StringBuffer和 StringBuilder。

1.StringBuilder的介绍

由于String的不可更改特性,为了⽅便字符串的修改,Java中⼜提供StringBuilder和StringBuffer类。 这两个类⼤部分功能是相同的,这⾥介绍StringBuilder常⽤的⼀些⽅法,其它需要⽤到了⼤家可参阅

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html

方法 说明
StringBuff append(String str) 在尾部追加,相当于String的+=,可以追加:bool、double、float、int、long、Object、String、char等类型
char charAt(int index) 获取index位置的字符
int length() 获取字符串的长度
int capacity() 获取底层保存字符串空间总的大小
void ensureCapacity(int mininimumCapacity) 扩容
void setCharAt(int index, char ch) 将index位置的字符设置为ch
int indexOf(String str) 返回str第一次出现的位置
int indexOf(String str, int fromIndex) 从fromIndex位置开始查找str第一次出现的位置
int lastIndexOf(String str) 返回最后一次出现str的位置
int lastIndexOf(String str, int fromIndex) 从fromIndex位置开始找str最后一次出现的位置
StringBuff insert(int offset, String str) 在offset位置插入:八种基类类型 & String类型
StringBuffer deleteCharAt(int index) 删除index位置字符
StringBuffer delete(int start, int end) 删除[start, end)区间内的字符
StringBuffer replace(int start, int end, String str) 将[start, end)位置的字符替换为str
String substring(int start) 从start开始一直到末尾的字符以String的形式返回
String substring(int start, int end) 将[start, end)范围内的字符以String的形式返回
StringBuffer reverse() 反转字符串
String toString() 将所有字符按照String的方式返回

2.StringBuffer的介绍

StringBuffer和StringBuilder从⽅法的功能上来说没有太⼤区别,这⾥不做单独介绍,可以查看官⽅⽂ 档:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuffer.html

StringBuffer采⽤同步处理,属于线程安全操作;⽽StringBuilder未采⽤同步处理,属于线程不安全操 作

以上就是我们的全部内容了!!!!

相关推荐
zzx2006__1 小时前
JavaScript最终考核
开发语言·前端·javascript
努力努力再努力wz1 小时前
【Qt入门系列】:QLabel控件详解:从文本显示到图片展示,再到内容布局与伙伴机制
android·开发语言·数据结构·数据库·c++·qt·mysql
小同志001 小时前
application.properties 和 application.yml
java·spring boot·spring·application.yml·.properities
甄心爱学习1 小时前
【项目实训(个人10)】
开发语言·前端·javascript
唐青枫1 小时前
Java JdbcTemplate 实战指南:用 Spring 轻量完成数据库增删改查
java·spring boot·spring
未秃头的程序猿1 小时前
别再让大模型单打独斗了!Java 多 Agent 协作实战:任务拆解+结果聚合
java·后端·ai编程
右耳朵猫AI1 小时前
Java & JVM技术周刊 2026年第20周
java·开发语言·jvm
人道领域1 小时前
【LeetCode刷题日记】538.把二叉搜索树转换为累加树
java·开发语言·后端·算法·leetcode
铁皮哥2 小时前
【后端开发】什么是守护线程,和普通线程有什么区别?
java·开发语言·数据库·人工智能·python·spring·intellij-idea