当前位置: 首页 > article >正文

完整版Java类型

1. 基本数据类型(Primitive Types)

Java 有 8 种基本数据类型,这些类型直接存储值,占用固定内存,效率较高。它们不属于类,没有方法或属性。

基本数据类型关键字大小取值范围
整数类型byte8 位-128 到 127
整数类型short16 位-32,768 到 32,767
整数类型int32 位-2^31 到 2^31-1
整数类型long64 位-2^63 到 2^63-1
浮点类型float32 位单精度浮点数
浮点类型double64 位双精度浮点数
字符类型char16 位单个 Unicode 字符
布尔类型boolean不确定truefalse

2. 引用类型(Reference Types)

引用类型用于存储对象的引用,而不是对象本身。引用类型包括接口数组、和枚举,它们在 Java 中用于更复杂的数据结构和逻辑控制。

Object obj 参数的含义

在方法定义 参数类型 Object 表示可以传入任何对象类型,包含:

  • 所有包装类(IntegerDoubleCharacter 等)
  • 自定义类
  • String 类型
  • 其他引用类型(如数组、集合等)

2.1 类(Class)

  • Java 中的大部分数据类型都是通过类创建的,类可以表示数据和行为(即属性和方法)。

  • 类的实例称为对象,类的类型即为引用类型。

  • 示例:StringIntegerDoublePerson 等自定义类。

    String str = "Hello, World!";
    Person person = new Person("John", 25);
    

2.2 接口(Interface)

  • 接口是一种特殊的引用类型,用于定义类的公共行为。

  • 接口不能实例化,但可以被类实现,接口类型可以用于多态性,指定对象的行为。

  • 示例:ListMapRunnable 等都是接口类型。

    List<String> list = new ArrayList<>();  // List 是接口,ArrayList 是其实现
    Runnable task = new MyRunnable();       // Runnable 是接口
    

2.3 数组(Array)

  • 数组也是一种引用类型,表示一组相同类型的元素。

  • 数组类型可以是基本数据类型数组(如 int[])或引用类型数组(如 String[])。

    int[] numbers = {1, 2, 3};           // int 类型的数组
    String[] names = {"Alice", "Bob"};    // String 类型的数组
    

2.4 枚举(Enum)

  • 枚举类型用于表示一组有限的、固定的常量值,通常用于表示状态或一组相关常量。

  • 枚举类型是一个特殊的类,它使用 enum 关键字定义。

    enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
    
    Day today = Day.MONDAY;
    

2.5 包装类(Wrapper Class)

  • 包装类是基本数据类型的对象版本,用于在需要对象类型的场景中使用基本类型的值。

  • 每种基本类型都有对应的包装类,例如 int 对应 Integerdouble 对应 Double

  • 包装类除了存储基本类型值,还提供了许多实用方法,如 parseInttoString 等。

    基本类型包装类
    intInteger
    doubleDouble
    booleanBoolean
    charCharacter
    byteByte
    shortShort
    longLong
    floatFloat
    Integer number = 42;
    Boolean flag = true;
    

所有包装类都具有 toString() 方法。这是因为所有包装类都继承自 Object 类,而 Object 类定义了 toString() 方法。因此,所有包装类(IntegerDoubleCharacter 等)都可以调用 toString() 方法。 

3. 使用包装类的场景

3.1. 集合框架的需求

使用原因:Java 集合框架(如 ListSetMap 等)只能存储对象,不能存储基本数据类型。当我们需要在集合中存储数值类型的数据时,必须使用包装类将基本类型转换为对象。这在统计、数据处理等需要存储大量数值的场景中非常常见。

示例场景

假设我们要存储一个班级中所有学生的分数,并计算平均分。我们可以使用 List<Integer> 来存储这些分数,因为集合只能存储对象类型。

List<Integer> scores = new ArrayList<>();
scores.add(85);  // 自动装箱,将 int 85 转换为 Integer 对象
scores.add(90);
scores.add(78);

// 计算平均分
int total = 0;
for (Integer score : scores) {
    total += score;  // 自动拆箱,将 Integer 转换为 int 参与运算
}
double average = total / (double) scores.size();
System.out.println("Average score: " + average);  // 输出: Average score: 84.3333

3.2. 需要表示 null 值的场合

使用原因:基本数据类型(如 intdouble)不能表示 null,而包装类可以。这在数据库查询、数据初始化和用户输入处理中非常有用,因为 null 可以表示“未赋值”或“无效”状态。例如,当从数据库读取用户年龄时,未填写的年龄字段可以用 null 表示,而不是一个默认数值(如 0),以避免数据误解。

示例场景

假设我们从数据库中查询用户的年龄,如果用户未填写年龄,数据库会返回 null。在 Java 中,我们可以用 Integer 来存储用户年龄,以便准确表示“未填写”的状态。

Integer age = null;  // 表示年龄未填写

// 判断是否填写了年龄
if (age == null) {
    System.out.println("Age is not provided.");
} else {
    System.out.println("Age: " + age);
}

3.3. 自动装箱和拆箱的便利性

使用原因:Java 支持自动装箱(基本类型自动转换为包装类)和自动拆箱(包装类自动转换为基本类型)。这种特性在集合和泛型的使用中尤其有用,因为我们可以直接操作基本类型的数值而无需手动转换,提升了代码的简洁性和可读性。

示例场景

假设我们有一个整数集合,想要将其中所有的分数加上 5 分。在遍历集合时,自动拆箱和装箱可以让我们直接进行数值操作,而无需手动转换。

List<Integer> scores = Arrays.asList(80, 85, 90);
List<Integer> updatedScores = new ArrayList<>();

for (Integer score : scores) {
    updatedScores.add(score + 5);  // 自动拆箱为 int,计算后自动装箱为 Integer
}
System.out.println("Updated scores: " + updatedScores);  // 输出: [85, 90, 95]

3.4. 使用包装类的实用方法和常量

使用原因:包装类提供了许多实用方法和常量,便于数值转换、格式化、边界检查等操作。例如,Integer.parseInt() 可以将字符串转换为整数,Double.isNaN() 用于判断数值是否为 NaNInteger.MAX_VALUE 表示 int 的最大值。这些方法和常量使得包装类在数据处理和异常值检测中非常方便。

示例场景

假设我们从用户输入中获取一个字符串,并将其解析为整数。如果用户输入的是非数字内容,系统需要抛出异常。我们还可以检查浮点运算是否为 NaN 值。

try {
    int value = Integer.parseInt("123");  // 将字符串 "123" 转换为整数
    System.out.println("Parsed value: " + value);
} catch (NumberFormatException e) {
    System.out.println("Invalid number format");
}

double result = 0.0 / 0.0;  // 计算无效值
if (Double.isNaN(result)) {
    System.out.println("Result is NaN (not a number)");
}

3.5. 泛型类型的需求

使用原因:Java 泛型只能接受引用类型,不能直接使用基本数据类型。这使得包装类在泛型类和方法中不可或缺。泛型设计使代码更具通用性和类型安全性,而包装类的引入确保了基本类型的兼容性。

示例场景

假设我们创建一个泛型类 Box,用于存储任意类型的数据。在泛型中,我们必须使用包装类来存储数值类型的数据。

class Box<T> {
    private T value;
    public Box(T value) { this.value = value; }
    public T getValue() { return value; }
}

Box<Integer> intBox = new Box<>(100);  // 必须使用 Integer 而非 int
System.out.println("Boxed value: " + intBox.getValue());  // 输出: Boxed value: 100

3.6. 多态性和对象方法调用

使用原因:包装类作为对象,能够享受面向对象编程的特性,例如多态性和对象方法调用。Java 的 Number 类是 IntegerDouble 等包装类的父类,可以用作这些包装类的通用类型。此外,包装类的对象可以直接调用许多实用方法。

示例场景

假设我们编写一个方法,接收 Number 类型的参数。这种多态性允许该方法接受 IntegerDouble 等所有包装类类型的数值参数。

public static void printDoubleValue(Number num) {
    System.out.println("Double value: " + num.doubleValue());
}

printDoubleValue(new Integer(10));   // 自动转为 double
printDoubleValue(new Double(15.5));

3.7. 比较和排序

使用原因:包装类实现了 Comparable 接口,因此支持对象的排序和比较操作。基本数据类型不具备对象的功能,而包装类提供的比较和排序接口使其可以直接用于集合的排序需求。在排序和优先级管理场景中,包装类广泛用于 ListSet 等集合的排序操作中。

示例场景

假设我们有一个学生分数的列表,想要按照分数从小到大排序。包装类 Integer 支持比较操作,可以直接在 Collections.sort() 中使用。

List<Integer> scores = Arrays.asList(88, 75, 90, 85);
Collections.sort(scores);  // 自动排序
System.out.println("Sorted scores: " + scores);  // 输出: [75, 85, 88, 90]

4.四种常用类型

4.1. String 类型

String 是 Java 中用于存储和处理文本数据的类。String 是不可变的,即一旦创建,字符串的内容就不能更改。每次对字符串进行修改时,都会创建一个新的 String 对象。

特点

  • 不可变性:字符串在创建后不可修改,修改字符串时会创建新的 String 对象。
  • 字符串池:Java 会将字符串字面量存储在一个字符串池(String Pool)中,以节省内存并提高性能。
  • 丰富的字符串操作方法String 类提供了多种方法,如 length()substring()charAt()equals()compareTo() 等,用于各种字符串操作。

常用方法

String str = "Hello, World!";

// 获取字符串长度
int length = str.length();  // 13

// 获取子字符串
String sub = str.substring(0, 5);  // "Hello"

// 字符串比较
boolean isEqual = str.equals("Hello, World!");  // true

// 转换为大写
String upper = str.toUpperCase();  // "HELLO, WORLD!"

在 Java 中,String 类型的对象可以通过两种方式创建:

  • 直接赋值(字符串字面量):例如 String str1 = "Java";
    • 这种方式会在 字符串池(String Pool) 中查找是否已有相同内容的字符串。
    • 如果字符串池中存在该内容的字符串,则会复用池中的对象。
    • 如果不存在,则会在字符串池中创建一个新对象。
  • 使用 new 关键字:例如 String str3 = new String("Java");
    • 这种方式会直接在 堆内存 中创建一个新的 String 对象,而不使用字符串池。
    • 即使内容相同,这样创建的对象也会与字符串池中的对象不同。

Stringchar 的相互转换

是的,Stringchar 类型可以相互转换。以下是常用的转换方法:

  • String 提取 char:可以使用 charAt(int index) 方法从 String 中提取指定位置的字符。

    String str = "Hello";
    char ch = str.charAt(1);  // 提取第二个字符 'e'
    
  • char 转换为 String:可以直接使用 Character.toString(char ch)String.valueOf(char ch),也可以通过字符串拼接的方式将 char 转换为 String

    char ch = 'A';
    String str = Character.toString(ch);  // 转换为 "A"
    // 或者使用
    String str2 = String.valueOf(ch);     // 转换为 "A"
    

示例

String str1 = "Java";
String str2 = "Java";
String str3 = new String("Java");

// str1 和 str2 指向字符串池中的同一对象
System.out.println(str1 == str2);  // true

// str3 是新创建的对象,虽然内容相同,但不是同一对象
System.out.println(str1 == str3);  // false
System.out.println(str1.equals(str3));  // true,内容相等

==equals 的区别

  • == 运算符:用于比较两个引用是否指向同一个对象,即比较两个对象的内存地址
    • str1 == str3 比较的是两个字符串引用是否指向同一对象。
    • 因为 str1 指向字符串池中的对象,而 str3 是一个新创建的对象,所以 str1 == str3false
  • equals 方法:用于比较两个字符串的内容是否相等。
    • str1.equals(str3) 比较的是两个字符串内容是否相同。
    • 即使两个字符串对象的引用不同,只要内容相同,equals 方法也会返回 true

  • String str1 = "Java";String str2 = "Java";

    • 这两个字符串都是通过字面量创建的,Java 作为字符串内容会被存储在字符串池中。
    • 因此,str1str2 指向的是字符串池中的同一个对象。
  • String str3 = new String("Java");

    • 使用 new 关键字创建的字符串对象总是会在堆内存中创建一个新对象。
    • 即使内容相同,str3 也是一个新的对象,不会指向字符串池中的对象。
    • 所以,str1 == str3 的结果为 false,因为它们不是同一个对象。


4.2. Character 类型

Characterchar 基本数据类型的包装类,用于表示单个字符。Character 提供了大量实用方法,用于处理字符的属性,如判断字符类型(字母、数字、空格等)或大小写转换。

特点

  • 字符操作方法Character 类提供了多种方法,用于判断字符类型、转换大小写等。
  • 字符编码Character 基于 Unicode 设计,因此可以表示世界上几乎所有语言的字符。

常用方法

Character charValue = Character.valueOf('A');  // 创建 Character 对象

// 判断是否为字母
boolean isLetter = Character.isLetter('A');  // true

// 判断是否为数字
boolean isDigit = Character.isDigit('1');  // true

// 转换为小写
char lower = Character.toLowerCase('B');  // 'b'

示例

Character a = Character.valueOf('A');
Character b = Character.valueOf('A');

// 字符在范围内时可能会缓存
System.out.println(a == b);  // true

// 转换大小写
System.out.println(Character.toLowerCase('Z'));  // 'z'
System.out.println(Character.toUpperCase('z'));  // 'Z'

4.3. Integer 类型

Integerint 基本数据类型的包装类。包装类允许在需要对象的场合使用基本类型,例如在集合框架中。Integer 提供了许多静态方法,方便整数的处理和转换。

特点

  • 缓存机制:Java 对 -128127 之间的整数进行缓存,若数值在此范围内且通过 Integer.valueOf 创建,则会返回相同的对象。
  • 常用静态方法Integer 提供了一些实用的静态方法,如 parseInt() 将字符串转为 intvalueOf() 创建 Integer 对象。

常用方法

Integer intValue = Integer.valueOf(10);  // 创建 Integer 对象

// 将字符串转换为 int
int parsedInt = Integer.parseInt("123");  // 123

// 获取 Integer 的最大值
int maxValue = Integer.MAX_VALUE;  // 2147483647

Integer.parseInt("123") 的转换规则

  • Integer.parseInt("123"):这个方法用于将字符串表示的数值转换为 int 类型。例如 Integer.parseInt("123") 的结果是 123

  • 非法输入的处理:如果输入的字符串不是有效的数字(如包含字母),则会抛出 NumberFormatException 异常,而不会进行任何转换。

    • 例如,Integer.parseInt("abc") 会抛出异常,而不是转换为 ASCII 码。

示例

Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
Integer c = Integer.valueOf(200);

// a 和 b 指向相同的缓存对象
System.out.println(a == b);  // true

// c 不在缓存范围内,创建新对象
System.out.println(a == c);  // false

4.4. Double 类型

Doubledouble 基本数据类型的包装类,表示双精度浮点数。Double 用于存储和处理小数数据,在需要对象的场合使用。

特点

  • 精度:双精度浮点数具有较高的精度,适合存储大范围或高精度的小数值。
  • NaN 和 InfinityDouble 提供了 NaN(非数值)和 Infinity(无穷大)等特殊值,用于表示非法或超出范围的结果。
  • 常用静态方法Double 提供了将字符串转换为 double 的方法 parseDouble(),还可以使用 Double.valueOf() 创建 Double 对象。

常用方法

Double doubleValue = Double.valueOf(5.5);  // 创建 Double 对象

// 将字符串转换为 double
double parsedDouble = Double.parseDouble("123.45");  // 123.45

// 检查是否为 NaN
boolean isNaN = Double.isNaN(0.0 / 0.0);  // true

// 获取 Double 的最大值
double maxValue = Double.MAX_VALUE;  // 1.7976931348623157E308

示例

Double x = Double.valueOf(10.5);
Double y = Double.valueOf(10.5);

// 浮点数没有缓存机制,不同对象
System.out.println(x == y);  // false

// 内容相同
System.out.println(x.equals(y));  // true

5.Vector 

Vector 是 Java 中的一种动态数组实现类,位于 java.util 包中,因此它属于引用类型。与 ArrayList 类似,Vector 允许动态调整容量以容纳更多的元素,但与 ArrayList 不同的是,Vector 是线程安全的,所有方法都被同步(synchronized)修饰,因此可以在多线程环境中安全使用。

Vector 的主要特点

  • 动态数组Vector 是一个动态数组,可以自动调整容量。与普通数组不同,Vector 的大小不是固定的,它会根据需要自动扩展。
  • 线程安全Vector 是线程安全的,因为它的所有方法都被 synchronized 修饰。这样保证了在多线程环境中不会发生并发修改问题。
  • 有序存储Vector 按照插入顺序存储元素,即添加元素的顺序就是迭代时的顺序。
  • 支持随机访问Vector 通过索引可以快速访问元素,适合需要频繁按索引访问的场景。
  • 扩容机制Vector 默认的初始容量是 10,当容量不够时,会自动扩展到原容量的 2 倍,或者可以指定扩容因子来控制增长速度。

5.1. 创建 Vector

Vector 提供了多种构造方法,允许我们指定初始容量和容量增量(扩展大小)。

  • Vector():创建一个默认容量为 10 的空向量。
  • Vector(int initialCapacity):创建一个指定初始容量的空向量。
  • Vector(int initialCapacity, int capacityIncrement):创建一个指定初始容量和容量增量的空向量。容量增量用于控制扩展速度。
import java.util.Vector;

public class VectorCreationExample {
    public static void main(String[] args) {
        Vector<String> vector1 = new Vector<>();  // 默认容量 10
        Vector<String> vector2 = new Vector<>(20);  // 指定初始容量为 20
        Vector<String> vector3 = new Vector<>(10, 5);  // 初始容量 10,扩展增量 5

        System.out.println("Vector1 capacity: " + vector1.capacity());  // 输出: 10
        System.out.println("Vector2 capacity: " + vector2.capacity());  // 输出: 20
        System.out.println("Vector3 capacity: " + vector3.capacity());  // 输出: 10
    }
}

5.2. 添加元素

Vector 提供了多种方法来添加元素:

  • add(E e):将元素添加到 Vector 的末尾。
  • add(int index, E element):在指定索引处插入元素。
  • addAll(Collection<? extends E> c):将另一个集合中的所有元素添加到 Vector
import java.util.Vector;

public class VectorAddExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Alice");  // 添加到末尾
        vector.add("Bob");

        vector.add(1, "Charlie");  // 在索引 1 处插入 "Charlie"

        Vector<String> moreNames = new Vector<>();
        moreNames.add("David");
        moreNames.add("Eve");

        vector.addAll(moreNames);  // 将 moreNames 中的元素添加到 vector

        System.out.println("Vector after additions: " + vector);  // 输出: [Alice, Charlie, Bob, David, Eve]
    }
}

5.3. 访问和查询元素

Vector 支持通过索引访问元素,还可以检查元素是否存在,获取首尾元素等。

  • get(int index):返回指定索引处的元素。
  • firstElement():返回第一个元素。
  • lastElement():返回最后一个元素。
  • contains(Object o):检查 Vector 是否包含指定的元素。
  • indexOf(Object o):返回指定元素首次出现的索引位置。
  • size():返回 Vector 中的元素数量。
import java.util.Vector;

public class VectorAccessExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Alice");
        vector.add("Bob");
        vector.add("Charlie");

        // 访问元素
        System.out.println("First element: " + vector.firstElement());  // 输出: Alice
        System.out.println("Last element: " + vector.lastElement());    // 输出: Charlie
        System.out.println("Element at index 1: " + vector.get(1));     // 输出: Bob

        // 查询元素
        System.out.println("Contains 'Alice'? " + vector.contains("Alice"));  // 输出: true
        System.out.println("Index of 'Charlie': " + vector.indexOf("Charlie"));  // 输出: 2
        System.out.println("Vector size: " + vector.size());  // 输出: 3
    }
}

5.4. 更新元素

使用 set(int index, E element) 方法可以替换 Vector 中指定索引位置的元素。

import java.util.Vector;

public class VectorUpdateExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Alice");
        vector.add("Bob");
        vector.add("Charlie");

        // 更新元素
        vector.set(1, "Bob Updated");  // 更新索引 1 的元素

        System.out.println("Vector after update: " + vector);  // 输出: [Alice, Bob Updated, Charlie]
    }
}

5.5. 删除元素

Vector 提供了多种方法删除元素,可以通过索引删除,也可以按值删除,还可以清空 Vector

  • remove(int index):删除指定索引位置的元素。
  • remove(Object o):删除首次出现的指定元素。
  • removeAll(Collection<?> c):删除 Vector 中包含在指定集合中的所有元素。
  • clear():清空 Vector,删除所有元素。
import java.util.Vector;

public class VectorRemoveExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Alice");
        vector.add("Bob");
        vector.add("Charlie");

        // 按索引删除元素
        vector.remove(1);  // 删除索引 1 的元素 "Bob"
        System.out.println("After removing index 1: " + vector);  // 输出: [Alice, Charlie]

        // 按值删除元素
        vector.remove("Alice");
        System.out.println("After removing Alice: " + vector);  // 输出: [Charlie]

        // 清空 Vector
        vector.clear();
        System.out.println("After clearing: " + vector);  // 输出: []
    }
}

5.6. 遍历 Vector

可以使用 for 循环、增强 for 循环或 Iterator 来遍历 Vector

  • iterator():返回 Vector 的迭代器。
  • elements():返回 Enumeration 对象,适用于旧版本的代码,但现在更推荐使用 Iterator
import java.util.Iterator;
import java.util.Vector;

public class VectorIterationExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Alice");
        vector.add("Bob");
        vector.add("Charlie");

        // 使用 for 循环
        System.out.println("Using for loop:");
        for (int i = 0; i < vector.size(); i++) {
            System.out.println(vector.get(i));
        }

        // 使用增强型 for 循环
        System.out.println("Using enhanced for loop:");
        for (String name : vector) {
            System.out.println(name);
        }

        // 使用 Iterator
        System.out.println("Using Iterator:");
        Iterator<String> iterator = vector.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

5.7. 扩容机制

Vector 的容量不足以容纳新元素时,会自动扩容。默认情况下,Vector 每次扩容为原容量的 2 倍。不过,可以通过构造方法指定扩展因子,控制每次扩容的增量。

import java.util.Vector;

public class VectorCapacityExample {
    public static void main(String[] args) {
        Vector<Integer> vector = new Vector<>(3, 2);  // 初始容量为 3,扩展因子为 2

        // 添加元素触发扩容
        for (int i = 1; i <= 5; i++) {
            vector.add(i);
            System.out.println("Capacity after adding element " + i + ": " + vector.capacity());
        }
    }
}


http://www.kler.cn/a/384371.html

相关文章:

  • LightGBM-GPU不能装在WSL,能装在windows上
  • 基于CNN-LSTM的时间序列数据预测,15个输入1个输出,可以更改数据集,MATLAB代码
  • 软件测试面试题及答案
  • 了解常见的反规范化技术手段
  • 【ChatGPT】如何通过逐步提示提高ChatGPT的细节描写
  • SpringBoot基础系列学习(二):日志
  • LInux基础 (一):Linux 系统重要命令拾遗
  • 在本地运行大模型:以Ollama为例
  • 2024最新版JavaScript逆向爬虫教程-------基础篇之Chrome开发者工具学习
  • 架构师:如何提高web网站的请求并发响应量?
  • Python中pandas组件学习总结
  • 【Linux】进程间通信(匿/命名管道、共享内存、消息队列、信号量)
  • 【go从零单排】实现枚举类型(Enum)
  • PyCharm中 argparse 库 的使用方法
  • jenkins流水线pipeline
  • Netty篇(学习前言)
  • mysql常见的一些配置项
  • C#-拓展方法
  • iOS开发 swift系列---一个视图数据修改后,如何刷新另外一个视图
  • 多机器人图优化:2024ICARA开源
  • 服务器数据恢复—分区结构被破坏的reiserfs文件系统数据恢复案例
  • 火山引擎云服务docker 安装
  • SpringBoot开发——8种读取配置文件信息的方式
  • 基于MPPT最大功率跟踪的光伏发电蓄电池控制系统simulink建模与仿真
  • 【ArcGISPro】单次将自己建立的工具箱添加至Arcpy中
  • C字符串 | 字符串处理函数 | 使用 | 原理 | 实现