《C++转Java快速入手系列》String篇:在C++里拼字符串像搬砖,在Java里拼字符串像玩乐高 —— 还是带垃圾回收的那种。

文章目录

《C++转Java快速入手系列》String篇

1、String简要介绍

Java与C++中的String类都是用来管理字符串的一种类型,但是他们在很多地方的设计是不同的,进而也导致了用法上也存在很多差异

  • C++中的String类是可变的,可以随意在一个String对象上用下标来进行修改,在Java中,String不能使用下标来进行访问,更不能以任何方式原地修改该字符串的内容。

  • 在Java中String是引用类型,且String类还是个特殊的引用类型,String被做了一个限制:他的引用的对象中的内容不可被修改。所以我们看到的修改String对象其实是换了一个常量进行引用,而非进行修改

  • 这种设计模式对标C++来说既有优势也有劣势:

    • 优点:不可变性带来线程安全、缓存哈希值、字符串常量池等好处,这些等到后面的多线程与数据结构篇章我们再做具体分析
    • 缺点:因不可变带来的频繁修改字符串时会创建大量的临时字符串,消耗的资源变多,进而导致性能低下。

    String类的设计:该类实现了多种接口,且用的是byte[] 数组来实现的

2、常用方法

以下对常用的需求进行分类来了解String的使用

2.1、字符串构造

String类提供的构造方式非常多,我们只需要掌握以下常用的三种即可:

  1. 使用常量串构造

String s1 = "hello bit";

  1. 直接new String 对象

String s2 = new String("hello bit");

  1. 使用字符数组进行构造

char[] arr = {'h','e','l','l','o','b','i','t'};

String s3 = new String(arr);

其实还有通过二进制内容来构造字符串的方法,我们在网络编程中再进行介绍

2.2、String对象的比较

字符串的比较,Java中总共提供了4种方式

  1. 用==比较是否引用同一个对象
java 复制代码
String s1 = "a";
String s2 = "b";
System.out.println(s1 == s2);

与任何一个引用类型一样,== 比较的是引用的地址是否相同(准确的说比较的其实是由地址经过加工生成的哈希码)

  1. boolean equals(String s2)方法:按照字典序比较
java 复制代码
String s1 = "a";
String s2 = "b";
System.out,println(s1.equals(s2));

这和我们之前在介绍数组时的Arrays.equals()的方法一样本质都是其共同父类Object中的方法,String也对其进行了重写,具体的比较的逻辑顺序如下:

  • 先检测这两个字符串是否为同一个对象,如果是则返回true
  • 检测传入的参数是否为String类型的对象,如果是则继续比较
  • 这两个字符串的长度是否相同,如果是则继续比较,反则返回false
  • 按照字典序,从前往后逐个字符进行比较
  1. int compareTo(String s)方法 :按字典序进行比较
java 复制代码
String s1 = "a";
String s2 = "b";
System.out,println(s1.compareTo(s2));

String类同样实现了Comparable接口,所以它也同样能用compareTo方法

与equals方法不同的是,equals返回的是boolean类型,而compareTo方法返回的是int类型

具体的比较逻辑如下:

  • 先按照字典次序大小比较,如果出现不等的字符,直接放这两个大小的差值
  • 如果前K个字符相等(这里的K为这两个字符串长度偏小的那一个值),返回两个字符串长度的差值
  1. int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写比较
java 复制代码
public class CompareToIgnoreCaseDemo {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "hello";
        String str3 = "World";
        String str4 = "apple";

        // 比较 str1 和 str2(忽略大小写)
        int result1 = str1.compareToIgnoreCase(str2);
        System.out.println("str1 和 str2 的比较结果: " + result1); // 输出 0

        // 比较 str1 和 str3(忽略大小写)
        int result2 = str1.compareToIgnoreCase(str3);
        System.out.println("str1 和 str3 的比较结果: " + result2); // 输出负数

        // 比较 str3 和 str4(忽略大小写)
        int result3 = str3.compareToIgnoreCase(str4);
        System.out.println("str3 和 str4 的比较结果: " + result3); // 输出正数
    }
}

2.3、字符串查找

以下是常用的查找方法整理:

方法 功能
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

2.4、转化

2.4.1、 数值与字符串的转换
2.4.1.1、数值 --> 字符串
  1. 直接用字符串的拼接:
java 复制代码
int a = 100;
String s1 = a + "";          // "100"
String s2 = 3.14 + "";       // "3.14"
String s3 = true + "";       // "true"
  1. 使用String的静态方法:String.valueOf()
java 复制代码
int a = 100;
String s1 = String.valueOf(a);        // "100"

double b = 2.718;
String s2 = String.valueOf(b);        // "2.718"

boolean c = false;
String s3 = String.valueOf(c);        // "false"

Object obj = null;
String s4 = String.valueOf(obj);      // "null"(不会抛异常)
  1. 数值类型的其包装类的静态方法:Integer.toString(int x)等
java 复制代码
String s1 = Integer.toString(255);        // "255"
String s2 = Double.toString(3.14);        // "3.14"
String s3 = Integer.toString(255, 16);    // "ff"  (指定进制)
String s4 = Integer.toBinaryString(10);   // "1010"
String s5 = Integer.toHexString(255);     // "ff"
2.4.1.2、字符串--> 数值
  1. 用数值类的包装类中的静态方法Integer.parseInt(String s):
java 复制代码
public class StringToNumber {
    public static void main(String[] args) {
        // 字符串转 int
        int i = Integer.parseInt("123");
        System.out.println(i);  // 123

        // 字符串转 double
        double d = Double.parseDouble("3.14");
        System.out.println(d);  // 3.14

        // 字符串转 long
        long l = Long.parseLong("9999999999");
        System.out.println(l);  // 9999999999

        // 字符串转 float
        float f = Float.parseFloat("2.718");
        System.out.println(f);  // 2.718
    }
}
  1. 当要转的类型要改进制时,第二个参数要传进制数
java 复制代码
public class RadixConversion {
    public static void main(String[] args) {
        // 十六进制字符串转 int
        int hex = Integer.parseInt("FF", 16);
        System.out.println(hex);  // 255

        // 二进制字符串转 int
        int bin = Integer.parseInt("1010", 2);
        System.out.println(bin);  // 10

        // 八进制字符串转 int
        int oct = Integer.parseInt("77", 8);
        System.out.println(oct);  // 63
    }
}
2.4.2、大小写转换

所用方法:String toUpperCase()、String toLowerCase()

java 复制代码
public class CaseConversion {
    public static void main(String[] args) {
        String original = "Hello World 2024";

        // 全转大写
        String upper = original.toUpperCase();
        System.out.println(upper);  // HELLO WORLD 2024

        // 全转小写
        String lower = original.toLowerCase();
        System.out.println(lower);  // hello world 2024
    }
}
2.4.3、字符串与数组的转换
2.4.3.1、 字符串 → 字符数组
  1. toCharArray()
java 复制代码
public class StringToCharArray {
    public static void main(String[] args) {
        String str = "Hello";
        char[] chars = str.toCharArray();

        for (char c : chars) {
            System.out.print(c + " "); // H e l l o
        }
    }
}
  1. charAt() 手动构建
java 复制代码
public class ManualToCharArray {
    public static void main(String[] args) {
        String str = "Java";
        char[] chars = new char[str.length()];
        for (int i = 0; i < str.length(); i++) {
            chars[i] = str.charAt(i);
        }
        // chars = {'J', 'a', 'v', 'a'}
    }
}
2.4.3.2、字符数组 → 字符串
  1. String构造方法
java 复制代码
public class CharArrayToString {
    public static void main(String[] args) {
        char[] chars = {'W', 'o', 'r', 'l', 'd'};
        String str = new String(chars);
        System.out.println(str); // World
    }
}
  1. 部分转化
java 复制代码
char[] chars = {'J', 'a', 'v', 'a', 'S', 'E'};
String part = new String(chars, 0, 4);  // offset=0, count=4
System.out.println(part); // Java
  1. String.valueOf(char[])
java 复制代码
String str = String.valueOf(chars);
2.4.4、格式化
java 复制代码
public class StringFormatDemo {
    public static void main(String[] args) {
        String name = "小明";
        int age = 20;
        double score = 95.5;

        // %s 字符串,%d 整数,%f 浮点数
        String result = String.format("姓名:%s,年龄:%d,成绩:%f", name, age, score);
        System.out.println(result);
        // 姓名:小明,年龄:20,成绩:95.500000
    }
}

2.5、字符串替换

使用指定新字符串替换掉已有的字符串数据

主要使用的方法如下:

方法 功能
String replaceAll(String regex,String replacement) 替换所有指定内容
String replaceFirst(String regex,String replacement 替换首个内容
java 复制代码
public class ReplaceDemo {
    public static void main(String[] args) {
        String text = "apple banana apple grape apple";

        // replaceAll:替换所有匹配的子串
        String all = text.replaceAll("apple", "orange");
        System.out.println(all);
        // orange banana orange grape orange

        // replaceFirst:只替换第一个匹配的子串
        String first = text.replaceFirst("apple", "orange");
        System.out.println(first);
        // orange banana apple grape apple
    }
}

2.6、字符串拆分

将一个完整的字符串按照指定的分隔符划分为若干个字符串

可用方法如下:

方法 功能
String[] split(String regex) 将字符串全部拆分
String[] split(String regex,int limit) 将字符串以指定的格式,拆分为limit组
java 复制代码
public class CsvSplitExample {
    public static void main(String[] args) {
        String csvLine = "张三,20,北京,";  // 最后一个字段为空

        // 默认 split:末尾空字段丢失
        String[] fields1 = csvLine.split(",");
        System.out.println("默认拆分:" + Arrays.toString(fields1));
        // [张三, 20, 北京]

        // 保留末尾空字段(limit = -1)
        String[] fields2 = csvLine.split(",", -1);
        System.out.println("保留空串:" + Arrays.toString(fields2));
        // [张三, 20, 北京, ]
    }
}

注意事项:

  • 如果分隔符为 "|","*","+"都得加上转义字符,前面加上"\"
  • 而如果是"",那么就得写成"\\"
  • 如果一个字符串中有多个分隔符,可用 "|"作为连字符

2.7、字符串截取

从一个完整字符串中截取部分内容,可用方法如下:

方法 功能
String substring(int beginIndex) 从指定索引截取到结尾
String substring(int beginIndex,int endIndex) 截取部分内容
java 复制代码
public class Main {
    public static void main(String[] args) {
        String s = "hello phoniex_tao";
        String s1 = s.substring(5);
        String s2 = s.substring(6,13);
        String s3 = s.substring(0,13);
        String s4 = s.substring(1,5);
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
        System.out.println(s4);
    }
}

注意事项:

  • 传入的参数实际截取的是按 前闭后开区间来进行的

3、 StringBuilder 和 StringBuffer

因为 String类型字符串的不可变性,我们在大量进行修改字符串时的效率会非常低,进而我们需要这两种新的字符串类型来满足这种需求,这两种类型的方法与String的方法几乎一摸一样 ,但是可以直接进行修改字符串

因此,一个常见的面试题诞生了:

String、StringBuffer、StringBuilder的区别有哪些?

  • String指向的对象内容不可修改, StringBuilder 和 StringBuffer的内容可修改
  • StringBuilder 和 StringBuffer的大部分功能是相似的
  • StringBuffer采用同步处理,有synchronized 修饰,属于线程安全操作,而StringBuilder未采用通不处理,属于线程不安全操作
  • 在不考虑多线程的情况下用StringBuilder即可,因为StringBuffer虽然线程安全,但一定程度上也限制了其效率

感谢阅读到这里,希望您有所收获,如果有要补充的地方并有好的建议可以评论提出。

相关推荐
会编程的吕洞宾2 小时前
Spring_Boot_3_3_的___Transactional__
java·后端·spring
雪度娃娃2 小时前
Asio——socket的创建和连接
linux·运维·服务器·c++·网络协议
轻刀快马2 小时前
讲明白Lambda 表达式的进化史
java·开发语言
故事和你912 小时前
洛谷-【图论2-2】最短路3
开发语言·数据结构·c++·算法·动态规划·图论
那个失眠的夜2 小时前
SpringBoot
java·开发语言·spring boot·spring·mvc·mybatis
yong99902 小时前
基于VC++的图像匹配金字塔算法
c++·算法·计算机视觉
范范@2 小时前
python基础-5大容器
开发语言·python
会编程的土豆2 小时前
Go 连接 Redis 代码详细解析
开发语言·redis·golang
测试员周周3 小时前
【AI测试路线图2】功能测试转 AI 测试:4~5 个月,一条最稳的路
开发语言·人工智能·python·功能测试·测试工具·单元测试·pytest