【JavaSE】万字详解字符串的秘密。。

本文详细介绍了Java中字符串的创建、比较相等、字符串常量池的概念,强调了字符串的不可变性,并探讨了字符、字节与字符串之间的关系。此外,还列举了字符串的常见操作,如比较、查找、替换、拆分、截取,以及StringBuffer和StringBuilder的使用。最后通过实例展示了如何消除字符串中重复的字符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 字符串的创建

常见的构造 String 的方式

// 方式一
String str = “Hello Bit”;
// 方式二
String str2 = new String(“Hello Bit”);
// 方式三
char[] array = {‘a’, ‘b’, ‘c’};
String str3 = new String(array);

字符串对象结构:
在这里插入图片描述

字符串对象是由一个数组对象和一个hash构成。

注意:java里面字符串最后是没有\n的,String为引用类型

2 字符串比较相等

我们来看一段代码:

public class Test {
    public static void main(String[] args) {
        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1 == str2);
    }
}

在这里插入图片描述

这里打印false是因为str1和str2引用分别指向了两个不同的对象,而==相当于是比较两个引用的值也就是两个对象的地址,不同对象的地址必然是不同的,所以会打印false

再来看另一段代码:

public class Test {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1 == str2);
    }
}

在这里插入图片描述

这里为什么会打印true呢,这里涉及到字符串常量池的问题等会再细讲。

Java 中要想比较字符串的内容, 必须采用String类提供的equals方法:

public static void main(String[] args) {
        String str1 = new String("Hello");
        String str2 = new String("Hello");
        System.out.println(str1.equals(str2));
        // System.out.println(str2.equals(str1)); // 或者这样写也行
    }

在这里插入图片描述
注意事项:
现在需要比较 str 和 “Hello” 两个字符串是否相等, 我们该如何来写呢?
💫上代码

public static void main(String[] args) {
        String str1 = new String("Hello");
        String str = new String("Hello");
        // 方式一
        System.out.println(str.equals("Hello"));
        // 方式二
        System.out.println("Hello".equals(str));
    }

虽然两种方式都能实现功能,但是通常我们会使用方式二,因为,如果str为null,那么方式一就会报错,而方式二不会,所以用方式二更加严谨。

在这里插入图片描述

注意:
“Hello” 这样的字面值常量, 本质上也是一个 String 对象, 完全可以使用 equals 等 String 对象的方法.

3 字符串常量池

字符串常量池是因为Java为String开辟的一块内存缓冲区,为了提高性能同时减少内存开销。在JVM中,字符串常量池由一个hash表实现。默认容量为1009。当字符串常量池中的存储比较多的字符串时,会导致hash冲突,从而每个节点形成长长的链表,导致性能下降。所以在使用字符串常量池时,一定要控制容量。

简单来说字符串常量池就是内存中专门用来存放字符串常量的区域,存放机制是按照哈希函数映射的哈希值来确定存放的位置,当位置重复后就在该位置下用链表的形式将数据串联起来从而方便进行查找。时间复杂度可以达到O(1)。

在这里插入图片描述
我们来通过几个例子来讲下字符串常量池:
🔥1:

public static void main(String[] args) {
        String str2 = "hello" ;
        String str1 = new String("hello");
        System.out.println(str1 == str2);
    }

在这里插入图片描述
接下来我们通过画图来了解整个程序运行过程:
在这里插入图片描述

第一句执行时,会先在字符串常量池查找有没有hello,没有则会在哈希值映射的下标下建立一个节点然后指向hello对象,第二句语句会产生两个对象,首先在常量池检查,发现有hello对象,所以不会在常量池重新创建hello对象,然后会创建一个新对象,同时这个对象会指向hello所在的数组

💡小知识:

若不同字符串被经过哈希函数映射到了相同下标,则会再建立一个节点并链接上一个节点,同时这个新节点会指向新的常量字符串对象。

🔥2:

public static void main(String[] args) {
        String str1 = "11";
        String str2 = new String("1") + new String("1");
        System.out.println(str1 == str2);
    }

在这里插入图片描述

str2字符串会将两个字符串对象拼接成一个StringBuilder对象,然后调用ToString方法转变成String对象然后将地址赋给str2

这里我们也可以看反汇编代码:(在输出文件窗口按住Shift+鼠标右键)
在这里插入图片描述

4 字符串不可变

字符串是一种不可变对象. 它的内容不可改变.
String 类的内部实现也是基于 char[] 来实现的, 它是由final修饰的,所以是不能进行修改的。但是 String 类并没有提供 set 方法之类的来修改内部的字符数组.

在这里插入图片描述

注意:
程序中要少用str+=这种形式的代码,这样只会不断创建新的对象从而导致效率降低。

5 字符、字节、字符串

5.1 字符与字符串

在这里插入图片描述代码示范:

public static void main(String[] args) {
        char[] arr = {'b','i','t'};
        String str1 = new String(arr);
        String str2 = new String(arr,1,2);
        char[] arr1 = str2.toCharArray();
        char c = str1.charAt(1);
        System.out.println(c);
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(Arrays.toString(arr1));

    }

在这里插入图片描述

5.2 字节与字符串

在这里插入图片描述
代码示例:

public static void main(String[] args){
        String str = "hello world";
        byte[] arr = str.getBytes();
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
        System.out.println(new String(arr));
    }

在这里插入图片描述

总结:

  • byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合
    针对二进制数据来操作.
  • char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候.

6 字符串常见操作

6.1 字符串比较

在这里插入图片描述
代码示例:

public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        String str3 = "hello1";
        System.out.println(str1 == str2);
        System.out.println(str1.equals(str2));
        System.out.println(str1.equalsIgnoreCase(str2));
        System.out.println(str1.compareTo(str2));
        System.out.println(str1.compareTo(str3));
    }

在这里插入图片描述

注意:当用comparaTo函数比较的一方长度比另一个字符串短且是另一个字符串的子集,那么会返回两个字符串长度的差值。

原码:
在这里插入图片描述

6.2 字符串查找

在这里插入图片描述
代码示例:

public static void main(String[] args) {
        String str1 = "hello";
        String str = "ll";
        System.out.println(str1.contains(str));
        System.out.println(str1.endsWith("o"));
        System.out.println(str1.lastIndexOf("ll",2));
        System.out.println(str1.indexOf("ll",0));
    }

在这里插入图片描述

注意:
lastIndexOf中的2代表从下标0到查找的字符串长度+2的长度4(即下标0到下标3)这一段字符串的结尾从后往前找。

6.3 字符串替换

在这里插入图片描述
代码示例:

public static void main(String[] args) {
        String str = "hello";
        System.out.println(str.replaceFirst("l","0"));
        System.out.println(str.replaceAll("l","0"));
    }

在这里插入图片描述

注意:
由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.

6.4 字符串拆分

在这里插入图片描述
代码示例:

public static void main(String[] args) {
        String str = "hello this world";
        String[] arr = str.split(" ");
        //将字符串分割为两部分
        String[] arr1 = str.split(" ",2);
        for (String s : arr) {
            System.out.println(s);
        }
        for (String s:arr1) {
            System.out.println(s);
        }
    }

在这里插入图片描述
🔥特殊字符的拆分:

'.' , ' | ',' * ',' + '这类字符则需要在前面加上\才能进行分割。

💫举个栗子:

public static void main(String[] args) {
        String str = "a.sdas.sd.ad.s.ads";
        String[] arr = str.split("\\.");
        for (String s:arr) {
            System.out.println(s);
        }

    }

在这里插入图片描述
多次分割:

public static void main(String[] args) {
        String str = "name=zhangsan&age=18";
        String[] arr = str.split("&");
        for (int i = 0; i < arr.length; i++) {
            String[] arr1 = arr[i].split("=");
            System.out.println(arr1[0]+"  "+arr1[1]);
        }

    }

在这里插入图片描述

6.5 字符串截取

在这里插入图片描述
代码示例:

public static void main(String[] args) {
        String str = "helloworld";
        String tep = str.substring(5);
        String tep1 = str.substring(0,5);
        System.out.println(tep);
        System.out.println(tep1);
    }

在这里插入图片描述

注意:
前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标

6.6 其他操作方法

在这里插入图片描述

注意:
1.数组里面是lengh属性,字符串是lengh()方法。
2.“”代表空字符串,但是也是对象,只是长度为0,占内存,在内存中分配一个空间,可以使用Object对象中的方法。
3.大小写转换只能转换字母。

💡实战:编写首字母大写的函数。

public static String firstUpper(String str){
        //保证str不为空字符串和null
        if("".equals(str) || str==null){
            return str;
        }
        if(str.length()>1){
            return str.substring(0,1).toUpperCase()+str.substring(1);
        }
        return str.toUpperCase();
    }
    public static void main(String[] args) {
        String str = "abcde";
        String ret = firstUpper(str);
        System.out.println(ret);
    }

在这里插入图片描述

7 StringBuffer 和 StringBuilder

通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和 StringBuilder类。频繁修改字符串的情况考虑使用StingBuffer。

StringBuffer与StringBuilder大部分功能是相似的,但是StringBuffer采用同步处理,属于线程安全操作,所以通常我们会使用StringBuffer。

StringBuffer使用方法:

    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("hello").append("bit");
        System.out.println(sb);
        sb.reverse();
        System.out.println(sb);
        sb.delete(3,8).insert(3,"你好");
        System.out.println(sb);

    }

在这里插入图片描述

用StringBuffer 或者 StringBuilder的好处:
1.可以对字符串进行修改。
2.能使用一些字符串所不具备的方法,比如反转,删除,插入字符串。

注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:

  • String变为StringBuffer:利用StringBuffer的构造方法或append()方法
  • StringBuffer变为String:调用toString()方法

💫实战:消除字符串中重复的字符

public static String deleteS(String str){
        if("".equals(str) || str == null){
            return str;
        }
        StringBuffer sb = new StringBuffer();
        sb.append(str.substring(0,1));
        for (int i = 1; i < str.length(); i++) {
            char c = str.charAt(i);
            if(sb.toString().contains(c+"") == true){
                continue;
            }
            sb.append(c);
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        String str = "adkjasdbdd";
        String ret = deleteS(str);
        System.out.println(ret);
    }

在这里插入图片描述

作者水平有限,若文章有任何问题欢迎私聊或留言,希望和大家一起学习进步!!!
创作不易,再次希望大家👍支持下,谢谢大家🙏

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值