文章目录
- 《C++转Java快速入手系列》String篇
-
- 1、String简要介绍
- 2、常用方法
-
- 2.1、字符串构造
- 2.2、String对象的比较
- 2.3、字符串查找
- 2.4、转化
-
- [2.4.1、 数值与字符串的转换](#2.4.1、 数值与字符串的转换)
-
- [2.4.1.1、数值 --> 字符串](#2.4.1.1、数值 --> 字符串)
- [2.4.1.2、字符串--> 数值](#2.4.1.2、字符串--> 数值)
- 2.4.2、大小写转换
- 2.4.3、字符串与数组的转换
-
- [2.4.3.1、 字符串 → 字符数组](#2.4.3.1、 字符串 → 字符数组)
- [2.4.3.2、字符数组 → 字符串](#2.4.3.2、字符数组 → 字符串)
- 2.4.4、格式化
- 2.5、字符串替换
- 2.6、字符串拆分
- 2.7、字符串截取
- [3、 StringBuilder 和 StringBuffer](#3、 StringBuilder 和 StringBuffer)
《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类提供的构造方式非常多,我们只需要掌握以下常用的三种即可:
- 使用常量串构造
String s1 = "hello bit";
- 直接new String 对象
String s2 = new String("hello bit");
- 使用字符数组进行构造
char[] arr = {'h','e','l','l','o','b','i','t'};
String s3 = new String(arr);
其实还有通过二进制内容来构造字符串的方法,我们在网络编程中再进行介绍
2.2、String对象的比较
字符串的比较,Java中总共提供了4种方式
- 用==比较是否引用同一个对象
java
String s1 = "a";
String s2 = "b";
System.out.println(s1 == s2);
与任何一个引用类型一样,== 比较的是引用的地址是否相同(准确的说比较的其实是由地址经过加工生成的哈希码)
- boolean equals(String s2)方法:按照字典序比较
java
String s1 = "a";
String s2 = "b";
System.out,println(s1.equals(s2));
这和我们之前在介绍数组时的Arrays.equals()的方法一样本质都是其共同父类Object中的方法,String也对其进行了重写,具体的比较的逻辑顺序如下:
- 先检测这两个字符串是否为同一个对象,如果是则返回true
- 检测传入的参数是否为String类型的对象,如果是则继续比较
- 这两个字符串的长度是否相同,如果是则继续比较,反则返回false
- 按照字典序,从前往后逐个字符进行比较
- 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为这两个字符串长度偏小的那一个值),返回两个字符串长度的差值
- 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、数值 --> 字符串
- 直接用字符串的拼接:
java
int a = 100;
String s1 = a + ""; // "100"
String s2 = 3.14 + ""; // "3.14"
String s3 = true + ""; // "true"
- 使用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"(不会抛异常)
- 数值类型的其包装类的静态方法: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、字符串--> 数值
- 用数值类的包装类中的静态方法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
}
}
- 当要转的类型要改进制时,第二个参数要传进制数
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、 字符串 → 字符数组
- 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
}
}
}
- 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、字符数组 → 字符串
- 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
}
}
- 部分转化
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
- 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虽然线程安全,但一定程度上也限制了其效率
感谢阅读到这里,希望您有所收获,如果有要补充的地方并有好的建议可以评论提出。