【JavaSE】String 类
【JavaSE】String 类
- 一、String 类是什么?
- 二、常用方法
- 2.1 字符串的构造方法
- 2.2 String对象的比较
- 2.2.1 == :比较是否引用同一个对象(对于String类型来说)
- 2.2.2 .equals(): boolean equals(Object anObject) 方法 —— 按照字典序比较
- 2.2.3 .compareTo():int compareTo(String s) 方法 —— 按照字典序进行比较
- 2.2.4 .compareToIgnoreCase():int compareToIgnoreCase(String str) 方法 ——与compareTo方式相同,但忽略大小写比较
- 2.3 字符串查找
- 2.4 转化
- 2.4.1 数值和字符串转化
- (1) 数值 转 字符串 :String.valueOf()
- (2) 字符串 转 数值:Integer.parseInt() 、 Double.parseDouble()等
- 2.4.2 大小写转换:.toUpperCase() / .toLowerCase()
- 2.4.3 字符串转数组:.toCharArray()
- 2.4.4 字符串格式化:.format()
- 2.5 字符串替换:.replace()
- 2.6 字符串拆分:.split()
- 2.7 字符串截取:.substring()
- 2.8 去掉字符串中的左右空白,保留中间空格 :.trim()
- 2.9 intern()方法
- 三、字符串的不可变性
- 3.1 String 不可变
- 3.2 字符串修改
- 三、 StringBuilder 和 StringBuffer
- 3.1 StringBuilder.append()实例:
- 3.2 **int capacity() :容量**
- 3.3 **当字符串越来越大的时候,创建对象的开销越来越大,StringBuilder优势越明显。**
- 3.4 capacity()实例
- 3.5 stringBuilder.setCharAt()
- 3.6 StringBuff insert(int offset, String str)
- 3.7 stringBuilder.delete(1,3);
- 3.8 stringBuilder.replace(1,3,"xx");
- 3.9 stringBuilder.reverse();
- 3.10 String、StringBuffer、StringBuilder的区别
- 四、 String类 oj
- 4.1 Leetcode387. 字符串中的第一个唯一字符
- 4.1.1 [LC387链接:字符串中的第一个唯一字符](https://leetcode.cn/problems/first-unique-character-in-a-string/)
- 4.1.2 题目解析
- 4.1.3 代码实现
- 4.2 HJ1 字符串最后一个单词的长度
- 4.2.1 [牛客链接: HJ1 字符串最后一个单词的长度](https://www.nowcoder.com/practice/8c949ea5f36f422594b306a2300315da?tpId=37&&tqId=21224&rp=5&ru=/activity/oj&qru=/ta/huawei/question-ranking)
- 4.2.2 题目解析
- 4.2.3 代码实现
- 4.3 Leetcode125. 验证回文串
- 4.3.1 [LC链接:Leetcode125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/description/)
- 4.3.2 题目解析
- 4.3.3 代码实现
一、String 类是什么?
String 类在Java中表示字符串的类型。
在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了String类。
二、常用方法
2.1 字符串的构造方法
public class Test {
public static void main(String[] args) {
// 直接newString对象
String str1 = new String("abcd");
// 使用常量串构造
String str2 = "hello";
// 使用字符数组进行构造
char[] chars = {'w','o','r','l','d'};
String str3 = new String(chars);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
// 使用byte数组进行构造
byte[] bytes = {97,98,99,100};
String str4 = new String(bytes);
System.out.println(str4);
}
}
输出结果:
【注意】
- String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:
public static void main(String[] args) {
// s1和s2引用的是不同对象 s1和s3引用的是同一对象
String s1 = new String("hello");
String s2 = new String("world");
String s3 = s1;
System.out.println(s1.length()); // 获取字符串长度---输出5
System.out.println(s1.isEmpty()); // 如果字符串长度为0,返回true,否则返回false
}
- 在Java中“”引起来的也是String类型对象
.length() 求字符串长度
// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());
2.2 String对象的比较
字符串的比较是常见操作之一,比如:字符串排序。Java中总共提供了4中方式:
2.2.1 == :比较是否引用同一个对象(对于String类型来说)
对于内置类型,比较的是变量中的值;对于引用类型 “ == ” 比较的是引用中的地址。
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 10;
// 对于基本类型变量,==比较两个变量中存储的值是否相同
System.out.println(a == b); // false
System.out.println(a == c); // true
// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
String s4 = s1;
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // false
System.out.println(s1 == s4); // true
}
注意:只要是“ ”引起来的,在内存中只有一份。
2.2.2 .equals(): boolean equals(Object anObject) 方法 —— 按照字典序比较
.equals()方法:String类型,比较字符串的内容
字典序:字符大小的顺序String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较,比如: s1.equals(s2)。
public boolean equals(Object anObject) {
// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
if (this == anObject) {
return true;
}
// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
if (anObject instanceof String) {
// 将anObject向下转型为String类型对象
String anotherString = (String)anObject;
int n = value.length;
// 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 4. 按照字典序,从前往后逐个字符进行比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("Hello");
// s1、s2、s3引用的是三个不同对象,因此==比较结果全部为false
System.out.println(s1 == s2); // false
System.out.println(s1 == s3); // false
// equals比较:String对象中的逐个字符
// 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true
// s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // false
}
2.2.3 .compareTo():int compareTo(String s) 方法 —— 按照字典序进行比较
.compareTo()方法:逐个字符,进行比较
应用场景:密码
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
- 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
- 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1
System.out.println(s1.compareTo(s3)); // 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}
2.2.4 .compareToIgnoreCase():int compareToIgnoreCase(String str) 方法 ——与compareTo方式相同,但忽略大小写比较
应用场景:验证码
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABc");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}
2.3 字符串查找
字符串查找也是字符串中非常常见的操作,String类提供的常用查找的方法:
方法 | 功能 |
---|---|
char charAt(int index) | 返回 index 位置上字符,如果 index 为负数或者越界,抛出 IndexOutOfBoundsException异常 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
char charAt(int index) | 返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常 |
int indexOf(int ch, int fromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-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 |
代码举例:
- char charAt(int index):给下标,拿字符
public class Test {
public static void main(String[] args) {
String str1 = "hello";
for (int i = 0; i < str1.length(); i++) {
char ch = str1.charAt(i);
//h
//e
//l
//l
//0
System.out.println(ch);
}
}
- int indexOf(int ch):给字符,拿下标
- int indexOf(String str)
- int indexOf(int ch, int fromIndex)
- int indexOf(String str, int fromIndex)
public class Test {
public static void main(String[] args) {
String str1 = "hello";
int index1 = str1.indexOf('l');//indexOf(int ch)方法;结果为2,表示 l的下标是2
System.out.println(index1);
int index2 = str1.indexOf("el");//indexOf(String str)方法;结果为1,表示 el的下标是2
System.out.println(index2);
int index3 = str1.indexOf('l',2);//indexOf(int ch,int fromIndex)方法
System.out.println(index3);
//结果为2,从下标为2的值 开始找l
int index4 = str1.indexOf("el",2);//indexOf(String str,int fromIndex)方法
System.out.println(index4);//-1:从下标为2的值,开始找el
}
- int lastIndexOf(int ch)
- int lastIndexOf(String str)
- int lastIndexOf(int ch, int fromIndex)
- int lastIndexOf(String str, int fromIndex)
public class Test {
public static void main(String[] args) {
String str1 = "ababcabcdabcdef";
//从后往前找,第1个c
int index1 = str1.lastIndexOf('c');//int lastIndexOf(int ch)方法
System.out.println(index1);//11
//从后往前找,第1个bc
int index2 = str1.lastIndexOf("bc");//int lastIndexOf(String str)方法
System.out.println(index2);
//11 10
//从12这个位置 往前走 第1个c
int index3 = str1.lastIndexOf('c',12);//int lastIndexOf(int ch,int fromIndex)方法
System.out.println(index3);//11
//从12这个位置 往前走 第1个bc
int index4 = str1.indexOf("ef",15);//int lastIndexOf(String str,int fromIndex)方法
System.out.println(index4);//-1
}
2.4 转化
2.4.1 数值和字符串转化
(1) 数值 转 字符串 :String.valueOf()
.valueOf()方法 将整数、小数、布尔类型值 变成 字符串。
public class Test {
public static void main(String[] args) {
String str1 = String.valueOf(1234);
String str2 = String.valueOf(12.34);
String str3 = String.valueOf(true);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
/*1234
12.34
true*/
}
.valueOf()方法 也能将 引用类型 变成 字符串。
class Student{
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
String str1 = String.valueOf(1234);
String str2 = String.valueOf(12.34);
String str3 = String.valueOf(true);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
/*1234
12.34
true*/
//把对象 转化成了 字符串的形式 —— 序列化
String str4 = String.valueOf(new Student("张三",10));
System.out.println(str4);
}
输出结果为:
(2) 字符串 转 数值:Integer.parseInt() 、 Double.parseDouble()等
public class Test {
public static void main(String[] args) {
// 字符串转数字
// 注意:Integer、Double等是Java中的包装类型
int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");
System.out.println(data1);
System.out.println(data2);
}
输出结果为:
2.4.2 大小写转换:.toUpperCase() / .toLowerCase()
public static void main(String[] args) {
String str1 = "hello";
String str2 = "HELLO";
// 小写转大写
System.out.println(str1.toUpperCase());
// 大写转小写
System.out.println(str2.toLowerCase());
//上面的转换,都是产生一个新的对象
}
输出结果:
2.4.3 字符串转数组:.toCharArray()
public static void main(String[] args) {
String s = "hello";
// 字符串转数组
char[] ch = s.toCharArray();
for (int i = 0; i < ch.length; i++) {
System.out.print(ch[i]);
}
System.out.println();
// 数组转字符串
String s2 = new String(ch);
System.out.println(s2);
}
输出结果:
2.4.4 字符串格式化:.format()
public static void main(String[] args) {
String s = String.format("%d-%d-%d", 2019, 9,14);
System.out.println(s);
}
输出结果:
2.5 字符串替换:.replace()
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
方法 | 功能 |
---|---|
String replaceAll(String regex, String replacement) | 替换所有的指定内容 |
String replaceFirst(String regex, String replacement) | 替换收个内容 |
代码举例说明:
1.将 l 全换为p
public class Test {
public static void main(String[] args) {
String str1 = "hello";
String ret = str1.replace('l','p');
System.out.println(str1);//该替换也是产生了新的对象,不是把原来的l替换为p
System.out.println(ret);
}
}
输出结果:
2.将所有的ab替换为kkk,等价于. replaceAll()方法
public class Test {
public static void main(String[] args) {
String str1 = "abababcdabcde";
String ret2 = str1.replace("ab","kkk");
System.out.println(str1);
//由于字符串是不可变对象, 替换不修改当前字符串(不是把原来的l替换为p),
//而是产生一个新的字符串
System.out.println(ret2);
}
输出结果:
3. 将第1个的ab替换为kkk
public class Test {
public static void main(String[] args) {
String str1 = "abababcdabcde";
String ret2 = str1.replaceFirst("ab","kkk");
System.out.println(str1);
System.out.println(ret2);
}
输出结果:
2.6 字符串拆分:.split()
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。可用方法如下:
方法 | 功能 |
---|---|
String[] split(String regex) | 返将字符串全部拆分 |
String[] split(String regex, int limit) | 将字符串以指定的格式,拆分为limit组 |
代码示例:
- String[ ] split(String regex)方法
public class Test {
public static void main(String[] args) {
String str1 = "zhangsan&lisi";
String[] ret = str1.split("&");//以 & 分割
for (String x : ret) {
System.out.println(x);
}
}
}
输出结果:
- String[ ] split(String regex, int limit)
public class Test {
public static void main(String[] args) {
String str1 = "zhangsan&lisi&wangwu&zhaoliu";
String[] ret = str1.split("&",2);//以 & 分割,最多分2组
for (String x : ret) {
System.out.println(x);
}
}
}
输出结果:
3. 多次分割
public class Test {
public static void main(String[] args) {
String str1 = "name=zhangsan&age=10";
String[] ret = str1.split("&");
for (String x: ret) {
//x: name=zhangsan age=10
String[] ret2 = x.split("=");
for (String x2:ret2) {
System.out.println(x2);
}
}
}
}
输出结果为:
4. 一次性分割:字符串有多个字符,同时进行分割(正则表达式原理)
public class Test {
public static void main(String[] args) {
String str1 = "name=zhangsan&age=10";
//正则表达式原理
String[] ret = str1.split("=|&");
for (String x : ret) {
System.out.println(x);
}
}
}
输出结果:
注意事项:
- 字符"|“,”*“,”+"都得加上转义字符,前面加上 “\” .
- 而如果是 “” ,那么就得写成 “\\” .
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符
特殊分割举例 1:对于**.**号来说,在Java中分割必须 转义(\\)
public class Test {
public static void main(String[] args) {
String str1 = "192.168.0.1";
String[] ret = str1.split("\\.");
for (String x : ret) {
System.out.println(x);
}
}
}
输出结果:
特殊分割举例 2:对于 \\ 号来说,在Java中分割必须 用 \\\\
public class Test {
public static void main(String[] args) {
String str1 = "192\\168\\0\\1";
String[] ret = str1.split("\\\\");
for (String x : ret) {
System.out.println(x);
}
}
}
输出结果:
2.7 字符串截取:.substring()
从一个完整的字符串之中截取出部分内容。可用方法如下:
方法 | 功能 |
---|---|
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分内容 |
public class Test {
public static void main(String[] args) {
String str = "abcdabcdef";
String ret1 = str.substring(4);//从4下标 开始截取
System.out.println(ret1);//abcdef
String ret2 = str.substring(4,6);
System.out.println(ret2);//从4下标 截取到6下标都得位置:[4,6)
//ab
}
}
输出结果:
2.8 去掉字符串中的左右空白,保留中间空格 :.trim()
(1)空白符包括:空格、换行、回车、制表符、翻页符、垂直制表符
(2).trim() 方法的应用场景:
针对用户输入的场景。前后两侧的空格,在程序眼中,一般都是属于“用户不小心”输入的一些无意义的数据
举例1:.trim() ,去掉字符串中的空格
public class Test {
public static void main(String[] args) {
tring str = " abc dabcdef ";
System.out.println(str);
String ret = str.trim();
System.out.println(ret);
}
}
输出结果:
举例 2:.trim() ,去掉字符串中的回车符 \t 和 回车符 \n
public class Test {
public static void main(String[] args) {
String str = "\t\t\thello\n\n\n";
System.out.println(str);
String ret = str.trim();
System.out.println(ret);
}
}
输出结果:
2.9 intern()方法
(1)intern() 作用:
当我们确认这个字符串常量经常使用的时候,就可以使用手动入池的操作,来优化程序,也能降低程序内存的开销。
(2)池(pool):
本身Java代码中的字符串常量(字面值,如hello);由于这样的常量可能会在很多代码中反复使用,就可以把它们放到“池”中,省下 创建这个常量 / 销毁 常量的开销。
- intern() 代码实例
public class Demo2 {
public static void main(String[] args) {
//此处的hello是字面值常量,本身就是在常量池中的。因此,编译器会将其直接替换为常量池中的地址
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);//true
char[] chars = {'h','e','l','l','o'};
String str3 = new String(chars);//让str3不是从常量池中取出的
System.out.println(str1 == str3);//false:说明当前str1、str3指向的引用不同
//==:比较的是 对象的身份,两个引用是否指向同一个引用
//而equals比较字符串的内容
str3 = str3.intern();//入池操作:将str3对象加入常量池
//此处发现hello就在常量池中,就拿到常量池中的引用,返回str3
System.out.println(str1 == str3);//true:str1、str3都是从常量池中取的
}
}
执行intern()操作的时候,就会先判定"hello"内容是否在常量池中存在:
(1)若存在,直接返回该常量池中的引用。
(2)若不存在,则把当前字符串添加到池子中,再返回引用。
- intern() 源码解析
三、字符串的不可变性
3.1 String 不可变
Java中,专门把String设计成“不可变对象”,字符串中的内容是不可改变。字符串不可被修改。
此处的不能修改指的是:String对象的本体不能修改,而不是指向String的引用不能修改。
- String是一种不可变对象 图解:
- String是一种不可变对象 原因:
3.2 字符串修改
注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。
public static void main(String[] args) {
String s = "hello";
s += " world";
System.out.println(s); // 输出:hello world
}
可以看待在对String类进行修改时,效率是非常慢的,因此:尽量避免对String的直接需要,如果要修改建议尽量使用StringBuffer或者StringBuilder。
b. 借助StringBuffer 和 StringBuilder
三、 StringBuilder 和 StringBuffer
由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的,这里介绍 StringBuilder常用的一些方法,其它需要用到了大家可参阅
StringBuilder在线文档
方法 | 功能 |
---|---|
StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取index位置的字符 |
int capacity() | 获取字符串的长度 |
char charAt(int index) | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index,char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastindexOf(String strint fromindex) | 从fromindex位置开始找str最后一次出现的位置 |
StringBuffer insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(int start, int end) | 删除[start,end)区间内的字符 |
StringBuffer replace(int start, int end, String str) | 将[start,end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int start, int end) | 将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
3.1 StringBuilder.append()实例:
public class Demo3 {
public static void main(String[] args) {
String s = "hello";
//这个操作本质上不是修改"hello",而是创建一个新的字符串”Hell0 world"
s +=" world";
System.out.println(s);
StringBuilder stringBuilder = new StringBuilder("hello");
//这个操作就是: 操作 StringBuilder对象本体,没有创建新的对象
stringBuilder.append(" world");
System.out.println(stringBuilder.toString());
}
}
输出结果:
3.2 int capacity() :容量
(1)创建StringBuilder的时候,会额外分配一部分内存空间,明明使用“ hello ”初始化,长度为5的空间足够了,但实际上会预申请更长的空间。
(2)后续如果需要追加操作,直接往里面添加就行;如果把空间填满了,还能自动扩容。
(3)StringBuilder的扩容是自行内部完成的,如果不手动设置,内部也会自动在capacity不够的时候触发扩容。
3.3 当字符串越来越大的时候,创建对象的开销越来越大,StringBuilder优势越明显。
输出结果:
3.4 capacity()实例
public class Demo5 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
//stringBuilder为空字符串,但它自带16个字节的空间
System.out.println(stringBuilder.capacity());
//stringBuilder.ensureCapacity():更改容量为128
stringBuilder.ensureCapacity(128);
System.out.println(stringBuilder.capacity());
}
}
输出结果:
3.5 stringBuilder.setCharAt()
public class Demo5 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello");
//stringBuilder为空字符串,但它自带16个字节的空间
System.out.println(stringBuilder.capacity());
//stringBuilder.ensureCapacity():更改容量为128
stringBuilder.ensureCapacity(128);
System.out.println(stringBuilder.capacity());
//将hello 下标为1的位置改为x
stringBuilder.setCharAt(1,'x');
System.out.println(stringBuilder.toString());
}
}
输出结果:
3.6 StringBuff insert(int offset, String str)
public class Demo6 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello");
//新插入的字符串的开头位置,就处于offset下标这里
stringBuilder.insert(1,"xxx");
System.out.println(stringBuilder.toString());
}
}
输出结果:
3.7 stringBuilder.delete(1,3);
public class Demo7 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello");
stringBuilder.delete(1,3);//[1,3)
System.out.println(stringBuilder.toString());
}
}
输出结果:
3.8 stringBuilder.replace(1,3,“xx”);
public class Demo8 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello");
//和 String 不同,直接修改对象的本体,不需要返回新的对象
stringBuilder.replace(1,3,"xx");
System.out.println(stringBuilder.toString());
}
}
输出:
3.9 stringBuilder.reverse();
public class Demo9 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello");
//字符串的逆序,修改对象自身
stringBuilder.reverse();
System.out.println(stringBuilder.toString());
}
}
输出:
3.10 String、StringBuffer、StringBuilder的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
- StringBuffer与StringBuilder大部分功能是相似的。
- StringBuffer 提供了 synchronized 操作,能够保证线程安全。
(StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。)
四、 String类 oj
4.1 Leetcode387. 字符串中的第一个唯一字符
4.1.1 LC387链接:字符串中的第一个唯一字符
4.1.2 题目解析
要找出 字符串中的第一个唯一字符:区分出哪些字符是唯一的,哪些字符不唯一。
- 先针对字符串的每一个字符遍历一遍。遍历的时候,统计每个字符出现的次数。
(1)先创建一个数组:长度为 int[256] arr = new int[256] -> 全0
取出a这个字符,ASCII码的值为:97
(2) 以 示例3 的 “aabb” 为例:
arr[97]++; a出现的次数: 0->1
arr[97]++; a出现的次数: 1->2
arr[98]++; b出现的次数: 0->1
arr[98]++; b出现的次数: 1->2
(3)此时,arr数组就记录了每个字符的出现次数。
其中数字下标,就表示“哪个字符”,数组元素表示该字符的出现次数。
- (1)再次从头到尾遍历字符串。
(2)依次去数组中取出 出现次数,看是否是1。
(3)找到这样的次数为1的元素,说明该字符即为所求。
(4)如果遍历完毕,都没有次数为1的,说明返回-1即可。
4.1.3 代码实现
class Solution {
public int firstUniqChar(String s) {
int[] arr = new int[256];
//1.统计每个字符出现的次数
for(int i = 0;i < s.length();i++) {
char c = s.charAt(i);
arr[c]++;
//将字符 c 对应的 ASCII 码作为索引,
//在 arr 数组中递增该字符的计数。
}
//2.上述代码,完成统计操作。接下来,再次遍历字符串,找到出现一次的字符串
for(int i = 0;i < s.length();i++){
char c = s.charAt(i);
//再次遍历字符串 s,检查每个字符 c 在 arr 中的计数:
if(arr[c] == 1) {
//如果 arr[c] == 1,说明该字符只出现一次,直接返回它的下标 i
return i;
}
}
//3.经过全部的遍历,都没找到出现一次的字符
return -1;
}
}
4.2 HJ1 字符串最后一个单词的长度
4.2.1 牛客链接: HJ1 字符串最后一个单词的长度
4.2.2 题目解析
要想知道 字符串最后一个单词的长度:需要找到最后一个单词是谁。
使用 lastIndexOf() 从后往前 找空格;空格开始的下一个位置,就是最后一个字符串的开始。
4.2.3 代码实现
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
//循环输入
Scanner scanner = new Scanner(System.in);//键盘输入
while(scanner.hasNext()){//按行读入
String line = scanner.nextLine();
//1.找到最后一个空格
int lastBlank = line.lastIndexOf(" ");
//2.从 空格 +1 的位置开始,到整行结束,就是最后一个单词
String lastWord = line.substring(lastBlank + 1);
//3.把字符串的长度打印出来
System.out.println(lastWord.length());
}
}
}
4.3 Leetcode125. 验证回文串
4.3.1 LC链接:Leetcode125. 验证回文串
4.3.2 题目解析
- 处理成小写
现成的方法:toLowerCase() - 针对每个字符进行判定,看当前这个字符是有效无效
(1)字母数字:有效,参与回文比较。
(2)其他符号:无效,直接跳过。 - 判断回文:双指针 — 头部的指针,尾部的指针(Java中的下标)
(1)头部指针指向元素和尾部指针指向元素是否相同;
(2)相同的话,头部指针++,尾部指针–
(3)从两边到中间,依次对比,完成比较过程。
很多 首尾比较问题 可利用双指针解决。
4.3.3 代码实现
class Solution {
//定义一个方法,判断指定字符时是否是有效的
public static boolean isValid(char c){
if((c >= 'a' && c <= 'z')||(c >= '0' && c<='9')){
//字符为字母或者数字
return true;
}
return false;
}
public boolean isPalindrome(String s) {
//1.把整个字符串转成小写
s = s.toLowerCase();
//2.通过双指针进行判断:
int left = 0;
int right = s.length() - 1;
while(left < right){
//3.从左往右,找到第一个合法的字符(数字、字母)
while(left < right && !isValid(s.charAt(left))){
//遇到不合法的字符,就++
left++; //当循环停下来的时候,left就指向了一个合法的字符
}
//4.从右往左,找到第一个合法的字符
while(left < right && !isValid(s.charAt(right))){
right--;//当循环停下来的时候,right也指向了一个合法的字符
}
//5.对比这两个字符是否相等
if(s.charAt(left) != s.charAt(right)){
//最左边的合法字符和最右边的合法字符不匹配,一定不是回文串!
return false;
}else{
//相等,继续比较下一组
left++;
right--;
}
}
//6.经过上述一系列的匹配,知道整个字符串都匹配完,
//都没有找到不符合回文的地方,就可以认为字符串就是回文串了。
return true;
}
}