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

内容介绍

  • 1 字符串的创建
  • 2 字符串比较相等
  • 3 字符串常量池
  • 4 字符串不可变
  • 5 字符、字节、字符串
    • 5.1 字符与字符串
    • 5.2 字节与字符串
  • 6 字符串常见操作
    • 6.1 字符串比较
    • 6.2 字符串查找
    • 6.3 字符串替换
    • 6.4 字符串拆分
    • 6.5 字符串截取
    • 6.6 其他操作方法
  • 7 StringBuffer 和 StringBuilder

1 字符串的创建

常见的构造 String 的方式

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

字符串对象结构:
【JavaSE】万字详解字符串的秘密。。_第1张图片

字符串对象是由一个数组对象和一个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);
    }
}

【JavaSE】万字详解字符串的秘密。。_第2张图片

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

再来看另一段代码:

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

【JavaSE】万字详解字符串的秘密。。_第3张图片

这里为什么会打印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)); // 或者这样写也行
    }

【JavaSE】万字详解字符串的秘密。。_第4张图片
注意事项:
现在需要比较 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,那么方式一就会报错,而方式二不会,所以用方式二更加严谨。

【JavaSE】万字详解字符串的秘密。。_第5张图片

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

3 字符串常量池

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

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

【JavaSE】万字详解字符串的秘密。。_第6张图片
我们来通过几个例子来讲下字符串常量池:
1:

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

【JavaSE】万字详解字符串的秘密。。_第7张图片
接下来我们通过画图来了解整个程序运行过程:
【JavaSE】万字详解字符串的秘密。。_第8张图片

第一句执行时,会先在字符串常量池查找有没有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);
    }

【JavaSE】万字详解字符串的秘密。。_第9张图片

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

这里我们也可以看反汇编代码:(在输出文件窗口按住Shift+鼠标右键)
【JavaSE】万字详解字符串的秘密。。_第10张图片

4 字符串不可变

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

【JavaSE】万字详解字符串的秘密。。_第11张图片

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

5 字符、字节、字符串

5.1 字符与字符串

【JavaSE】万字详解字符串的秘密。。_第12张图片代码示范:

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));

    }

【JavaSE】万字详解字符串的秘密。。_第13张图片

5.2 字节与字符串

【JavaSE】万字详解字符串的秘密。。_第14张图片
代码示例:

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));
    }

【JavaSE】万字详解字符串的秘密。。_第15张图片

总结:

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

6 字符串常见操作

6.1 字符串比较

【JavaSE】万字详解字符串的秘密。。_第16张图片
代码示例:

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));
    }

【JavaSE】万字详解字符串的秘密。。_第17张图片

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

原码:
【JavaSE】万字详解字符串的秘密。。_第18张图片

6.2 字符串查找

【JavaSE】万字详解字符串的秘密。。_第19张图片
代码示例:

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));
    }

【JavaSE】万字详解字符串的秘密。。_第20张图片

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

6.3 字符串替换

【JavaSE】万字详解字符串的秘密。。_第21张图片
代码示例:

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

【JavaSE】万字详解字符串的秘密。。_第22张图片

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

6.4 字符串拆分

【JavaSE】万字详解字符串的秘密。。_第23张图片
代码示例:

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);
        }
    }

【JavaSE】万字详解字符串的秘密。。_第24张图片
特殊字符的拆分:

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

举个栗子:

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);
        }

    }

【JavaSE】万字详解字符串的秘密。。_第25张图片
多次分割:

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]);
        }

    }

【JavaSE】万字详解字符串的秘密。。_第26张图片

6.5 字符串截取

【JavaSE】万字详解字符串的秘密。。_第27张图片
代码示例:

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);
    }

【JavaSE】万字详解字符串的秘密。。_第28张图片

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

6.6 其他操作方法

【JavaSE】万字详解字符串的秘密。。_第29张图片

注意:
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);
    }

【JavaSE】万字详解字符串的秘密。。_第30张图片

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);

    }

【JavaSE】万字详解字符串的秘密。。_第31张图片

用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);
    }

【JavaSE】万字详解字符串的秘密。。_第32张图片

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

你可能感兴趣的