首页 > 编程语言 >JavaSE5️⃣核心类 - String 相关类

JavaSE5️⃣核心类 - String 相关类

时间:2023-02-21 16:47:29浏览次数:39  
标签:编码 String JavaSE5 字符 核心 char 字符串 public

1、String

1.1、简介

String:字符串

Java 最常用的引用类型之一。

  1. 底层实现private final char[]。即不可变的字符数组,且没有任何相关修改方法。
  2. 不可变
    1. 字符串对象创建后无法改变。
    2. 任何对字符串的修改,底层都会创建新的字符串对象并返回引用。

1.1.1、创建方式

字面量 new
含义 双引号 "" 包围 new String(参数)
存储位置 常量池
创建过程 检查常量池中是否存在,是则返回引用,否则创建并放在常量池中 每次创建一个全新的字符串对象
说明 允许 JVM 优化内存分配,节省空间 参数可以是字符串、字符数组、字节数组

1.1.2、特殊值(空)

特殊的字符串值

  1. 空值null):任何引用对象都可指向 null,表示不存在

  2. 空串""):值为空的有效字符串对象。

  3. 空格串" "):值为若干个空格。

    String str1 = "ABC";
    String str2 = null;
    String str3 = "";
    

1.1.3、转义字符

转义字符\

将字符串中的特殊符号进行转义,避免程序识别错误。

  • 常用转义字符

    特殊符号 对应转义字符
    " \"
    ' \'
    \ \\
    换行 \n
    回车 \r
    tab \t
    Unicode 字符 \u####
  • 示例

    // 三个字符:A 换行符 好
    String str = "A\n\u597D";
    

1.1.4、多行字符串

两种书写形式

  1. 拼接:使用 + 拼接多个字符串。

  2. 三引号:(Java 13)使用一对 """ 包围字符串内容。

    String str1 = "SELECT * " +
        "FROM tb_user" +
        "WHERE id = 1;";
    
    String str2 = """
        SELECT *
        FROM tb_user
        WHERE id = 1;
    """;
    

1.2、基础操作

1.2.1、比较

字符串比较

  1. 比较内容:使用 equals()(而不是 ==)。
  2. 忽略大小写euqalsIgnoreCase()

示例:对于内容相同的字符串,分析 == 的结果。

  1. 字面量:s2 和 s1 是对常量池中同一个字符串对象的引用。

    String s1 = "hello";
    String s2 = "hello";
    
    System.out.println(s1.equals(s2));	// true
    System.out.println(s1 == s2);	// true
    
  2. 字面量 & new:s1 和 s2 分别在常量池和堆中,是不同的对象。

    String s1 = "hello";
    String s2 = new String("hello");
    
    System.out.println(s1.equals(s2));	// true
    System.out.println(s1 == s2);	// false
    
  3. new:s1 和 s2 均创建了新的字符串对象,是不同的对象。

    String s1 = new String("hello");
    String s2 = new String("hello");
    
    System.out.println(s1.equals(s2));	// true
    System.out.println(s1 == s2);	// false
    

1.2.2、判空

  1. isEmpty():(Java 6)判断字符串长度是否为 0,即空串("")。

    "".isEmpty();		// true
    " ".isEmpty();		// false
    "\n".isEmpty();		// false
    
  2. isBlank():(Java 11)判断字符串是否空白

    1. 空串("")、空格串(" ")、缩进符 \t,回车符 \r,换行符 \n

    2. 可理解为是否包含有意义字符。

      "".isBlank();		// true
      " ".isEmpty();		// true
      "\n".isBlank();		// true
      

1.2.3、分割

分割字符串

  1. 方法签名:传入正则表达式,返回分割后的字符串数组。

    public String[] split(String regex) {}
    
  2. 示例

    String s = "A,B,C";
    String[] result = s.split(","); // ["A", "B", "C"]
    

1.3、类型转换

1.3.1、valueOf → 字符串

valueOf():可以将引用类型、基本类型、字符数组转换为 String。

引用类型

本质:对象.toString()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

基本类型

  1. 数值:本质是 包装类型.toString(xxx)

    public static String valueOf(int i) {}
    public static String valueOf(long l) {}
    public static String valueOf(float f) {}
    public static String valueOf(double d) {}
    
  2. 布尔

    public static String valueOf(boolean b) {
        return b ? "true" : "false";
    }
    
  3. 字符:本质是 new String() 的重载方法。

    public static String valueOf(char c) {
        char data[] = {c};
        return new String(data, true);
    }
    

字符数组

本质new String() 的重载方法。

// 整个数组
public static String valueOf(char data[]) {
    return new String(data);
}

// 指定起始索引和字符个数
public static String valueOf(char data[], int offset, int count) {
    return new String(data, offset, count);
}

1.3.2、parseXxx() → 其它

除了 Character 类,各包装类中定义了 parseXxx() 方法。

  1. 整数型:Byte、Short、Integer、Long 类中定义,可指定进制。

    // 普通转换:四种类型
    public static 基本类型 parseXxx(String s)
        throws NumberFormatException {}
    
    public static 基本类型 parseXxx(String s, int radix)
        throws NumberFormatException {}
    
    
    // 无符号转换:Integer、Long
    public static 基本类型 parseUnsignedXxx(String s)
        throws NumberFormatException {}
    
    public static 基本类型 parseUnsignedXxx(String s, int radix)
        throws NumberFormatException {}
    
  2. 浮点型:Float 和 Double 类中定义。

    public static 基本类型 parseXxx(String s) 
        throws NumberFormatException {}
    
  3. 布尔型:Boolean 类中定义。

    public static boolean parseBoolean(String s) {}
    

1.3.3、字符数组

char[] → String

  1. 方法签名:String 的构造方法。

    1. 对 char[] 的修改不会影响 String。
    2. 原因:new String() 创建字符串实例时,不会直接引用传入的 char[],而是复制一份。
    3. 传入的 char[] 和 String 使用的 char[] 是两个不同的数组。
    public String(char value[]) {}
    public String(char value[], int offset, int count) {}
    
  2. 示例

    char[] chs = {'a', 'b', 'c', 'd'};
    
    String s1 = new String(chs);		// abcd
    String s2 = new String(chs, 0, 2);	// ab
    

String → char[]

  1. 方法签名:String 定义的实例方法。

    public char[] toCharArray() {}
    
  2. 示例

    String str = "Hello";
    
    str.toCharArray();	// ['H', 'e', 'l', 'l', 'o']
    

1.3、子串操作

Hint:索引从 0 开始

1.3.1、搜索子串

判断包含

  1. 方法签名:参数为 CharSequence 接口,String 是其实现类。

    public boolean contains(CharSequence s) {}
    
  2. 示例

    "Hello".contains("lo");	// true
    "Hello".contains("ol");	// false
    

索引

  1. 方法签名

    // 首次出现
    public int indexOf(String str) {}
    // 最后一次出现
    public int lastIndexOf(String str) {}
    
  2. 示例

    "Hello".indexOf("l");	// 2
    "Hello".lastIndexOf("l");	// 3
    

判断前后缀

  1. 方法签名

    // 是否以prefix开头
    public boolean startsWith(String prefix) {}
    // 是否以suffix结尾
    public boolean endsWith(String suffix) {}
    
  2. 示例

    "Hello".startsWith("He"); // true
    "Hello".endsWith("lo"); // true
    

1.3.2、提取子串

提取子串

  1. 方法签名

    // 指定索引之后
    public String substring(int beginIndex) {}
    // 指定索引范围(前闭后开)
    public String substring(int beginIndex, int endIndex){}
    
  2. 示例

    "Hello".substring(2);		// "llo"
    "Hello".substring(2, 4);	// "ll"
    

移除首尾空白字符

  1. trim():包含英文空格 、缩进符 \t,回车符 \r,换行符 \n

    "  \tHello\r\n ".trim();	// "Hello"
    
  2. strip():(Java 11+)在 trim() 的基础上,移除中文空格字符 \u3000

    "\u3000Hello\u3000".strip();	// "Hello"
    " Hello ".stripLeading();		// "Hello "
    " Hello ".stripTrailing();		// " Hello"
    

1.3.3、替换子串

根据字符或字符串

  1. 方法签名

    // 使用 newChar 替换掉所有的 oldChar
    public String replace(char oldChar, char newChar) {}
    
    // 使用 replacement 替换掉所有的 target
    public String replace(CharSequence target,
                          CharSequence replacement) {}
    
  2. 示例

    String s = "hello";
    
    s.replace('l', 'x');	// hexxo
    s.replace("l", "xx");	// hexxxxo
    

根据正则表达式

  1. 方法签名

    // 使用 replacement 替换掉首次匹配的 regex
    public String replaceFirst(String regex,
                               String replacement) {}
    // 使用 replacement 替换掉所有匹配的 regex
    public String replaceAll(String regex,
                             String replacement) {}
    
  2. 示例

    String s2 = "A,,B;C ,D";
    s2.replaceFirst("[,;\\s]+", ",");   // "A,B;C ,D"
    s2.replaceAll("[,;\\s]+", ",");     // "A,B,C,D"
    

编码

  1. ASCII 编码

    1. 美国国家标准学会(American National Standard Institute:ANSI)制定。
    2. 英文字母、数字和常用符号的编码。
    3. 占用一个字节,编码范围从 0127,最高位始终为 0
    4. 示例:字符'A'的编码是0x41,字符'1'的编码是0x31
    5. 说明
      1. 一个字节不足以纳入汉字等其它语言的编码。
  2. GB2312 标准

    1. 使用 2 个字节表示一个汉字。
    2. 第一个字节的最高位始终为1,以便和ASCII编码区分开。
    3. 示例:汉字'中'GB2312编码是0xd6d0
    4. 说明:不同国家编码的标准不统一,同时使用则会产生冲突。
  3. Unicode 编码

    1. 为了统一全球所有语言的编码,全球统一码联盟发布

    2. 把世界上主要语言纳入同一个编码。

    3. 需要 2 个或者更多字节表示.

    4. 示例:对比中英文字符在 ASCIIGB2312Unicode的编码

      1. 英文字符:英文字符的 Unicode 编码就是简单地在前面添加一个00字节。

                 ┌────┐
        ASCII:   │ 41 │
                 └────┘
                 ┌────┬────┐
        Unicode: │ 00 │ 41 │
                 └────┴────┘
        
      2. 中文字符'中'GB2312编码和Unicode编码:

                 ┌────┬────┐
        GB2312:  │ d6 │ d0 │
                 └────┴────┘
                 ┌────┬────┐
        Unicode: │ 4e │ 2d │
                 └────┴────┘
        
  4. UTF-8 编码

    1. 英文字符的Unicode编码高字节总是00,包含大量英文的文本会浪费空间。
    2. 节省空间UTF-8编码是一种变长编码,把固定长度的Unicode编码变成1~4字节的变长编码。
      1. 英文字符'A'UTF-8编码变为0x41,正好和ASCII码一致
      2. 中文'中'UTF-8编码为3字节0xe4b8ad
    3. 容错能力强:若传输过程中某些字符出错,不会影响后续字符。因为UTF-8编码依靠高字节位来确定一个字符究竟是几个字节,它经常用来作为传输编码。

Java 的 char 在内存中以 Unicode 编码表示,一个 char 占用两个字节的 Unicode 编码。

2、拼接字符串

+

+:使用 + 连接多个任意类型的变量。

  1. 说明:连接之前,其它数据类型会先自动转型为 String
  2. 底层:StringBuilder.append()

String.join()

join():使用指定分隔符,连接多个字符串数组元素。

  1. 方法签名

    public static String join(CharSequence delimiter,
                              CharSequence... elements) {}
    
  2. 示例

    String[] arr = {"A", "B", "C"};
    String s = String.join("***", arr); // "A***B***C"
    

StringBuilder

Java编译器对 String 做了特殊处理,可以直接用 + 拼接字符串。

考察下面的循环代码:

String s = "";
for (int i = 0; i < 1000; i++) {
    s = s + "," + i;
}

虽然可以直接拼接字符串,但是,在循环中,每次循环都会创建新的字符串对象,然后扔掉旧的字符串。这样,绝大部分字符串都是临时对象,不但浪费内存,还会影响GC效率。

为了能高效拼接字符串,Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder中新增字符时,不会创建新的临时对象:

StringBuilder sb = new StringBuilder(1024);
for (int i = 0; i < 1000; i++) {
    sb.append(',');
    sb.append(i);
}
String s = sb.toString();

StringBuilder还可以进行链式操作:

// 链式操作

Run

如果我们查看StringBuilder的源码,可以发现,进行链式操作的关键是,定义的append()方法会返回this,这样,就可以不断调用自身的其他方法。

仿照StringBuilder,我们也可以设计支持链式操作的类。例如,一个可以不断增加的计数器:

// 链式操作

注意:对于普通的字符串+操作,并不需要我们将其改写为StringBuilder,因为Java编译器在编译时就自动把多个连续的+操作编码为StringConcatFactory的操作。在运行期,StringConcatFactory会自动把字符串连接操作优化为数组复制或者StringBuilder操作。

你可能还听说过StringBuffer,这是Java早期的一个StringBuilder的线程安全版本,它通过同步来保证多个线程操作StringBuffer也是安全的,但是同步会带来执行速度的下降。

StringBuilderStringBuffer接口完全相同,现在完全没有必要使用StringBuffer

StringJoiner

要高效拼接字符串,应该使用StringBuilder

很多时候,我们拼接的字符串像这样:

// Hello Bob, Alice, Grace!

Run

类似用分隔符拼接数组的需求很常见,所以Java标准库还提供了一个StringJoiner来干这个事:

import java.util.StringJoiner;

Run

慢着!用StringJoiner的结果少了前面的"Hello "和结尾的"!"!遇到这种情况,需要给StringJoiner指定“开头”和“结尾”:

import java.util.StringJoiner;

Run

String.join()

String还提供了一个静态方法join(),这个方法在内部使用了StringJoiner来拼接字符串,在不需要指定“开头”和“结尾”的时候,用String.join()更方便:

String[] names = {"Bob", "Alice", "Grace"};
var s = String.join(", ", names);

对比

String StringBuffer StringBuilder
可变
线程安全 ✔(synchronized)
性能 低(不可变,拼接/更改时频繁创建新对象) 中(同步锁)
存储 字符串常量池

标签:编码,String,JavaSE5,字符,核心,char,字符串,public
From: https://www.cnblogs.com/secretmrj/p/17141514.html

相关文章