【425-446】String
2022-01-23 13:57:00 # JavaSE

概要

  1. String 属于引用类型,不属于基本类型
  2. 用双引号括起来的字符串,例如“abs”,”def”都是存储在“方法区”的“字符串常量池”中
  3. 使用“+”进行字符串拼接,如String s = “a”+“b”,会在方法去产生两个字符串对象,在堆内存中产生一个String s对象,频繁使用导致内存空间的浪费
  4. 面试题:String为什么是不可变的?
    我看过源代码,String类中有一个byte[ ]数组,这个byte[ ]数组采用了final修饰,因为数组一旦创建长度不可变。并且被final修饰的引用一旦指向某个对象之后,不可再指向其它对象,所以String是不可变的!
     "abc”无法变成"abcd"  
    
  5. StringBuiLder/StringBuffer为什么是可变的呢?
    我看过源代码,StringBuffer/StringBuiLder内部实际上是一个byte[ ]数组,这个byte[ ]数组没有披final修饰,StringBuffer/StringBuilder的初始化容量我记得应该是16,当存满之后会进行扩容,底层调用了数组拷贝的方法System.arraycopy()…是这样扩容的。所以stringBuilder/StringBuffer适合于使用字符串的频繁拼接操作。

String字符串的存储原理

01

这里本该有一张图

1
2
3
4
5
6
7
8
9
10
11
12
13
public class _425_String字符串的存储原理 {
public static void main(String[] args) {
// 以下两行在底层创建了三个字符串对象, 都存储在字符串常量池中
String s1 = "abcdef";
String s2 = "abcdef" + "xy";

// new对象的时候一定在堆内存中开辟空间
// “xy” 一定在字符串常量池中有一份
String s3 = new String("xy");

}
}

02

这里本该有一张图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class _426_String字符串的存储原理 {
public static void main(String[] args) {
//
User user = new User(110, "张三");

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

//
String x = new String("xyz");
String y = new String("xyz");
System.out.println(x == y); // false
// 所以String重写equals方法,使用equals方法比较
System.out.println(x.equals(y));

// 这样写可以避免空指针异常
System.out.println("xyz".equals(x));

}
}

class User{
int Id;
String name;

public User(int id, String name) {
Id = id;
this.name = name;
}
}

03

1
2
3
4
5
6
7
8
9
10
11
12
13
public class _428_String面试题中创建了几个对象 {
public static void main(String[] args) {
/*
一共3个对象:
方法区字符串常量池有1个“hello”
堆内存中有2个String对象
*/

String s1 = new String("hello");
String s2 = new String("hello");
}
}

String类的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class _429_String类的构造方法 {
public static void main(String[] args) {
//
String s = new String("hello");
System.out.println(s);
//
String s1 = "abc";
System.out.println(s1);
//
byte[] bytes = {97,98,99};
String s2 = new String(bytes);
System.out.println(s2);
//
String s3 = new String(bytes,1,2);
System.out.println(s3);
//
char[] chars = {'a','b','c','d','e'};
String s4 = new String(chars);
System.out.println(s4);
//
String s5 = new String(chars,2,3);
System.out.println(s5);
}
}

String类中的方法

charAt()

1
2
3
4
5
6
7
public class _430_String类的charAt方法 {
public static void main(String[] args) {
char c = "abc".charAt(2);
System.out.println(c);
}
}

compareTo()

按照字典序比较大小
相等返回0
小返回负数
大返回正数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class _431_String类的compareTo方法 {
public static void main(String[] args) {
int res = "abc".compareTo("abc");
System.out.println(res); // 0

int res1 = "abc".compareTo("abcd");
System.out.println(res1);

int res2 = "abc".compareTo("ac");
System.out.println(res2);

int res3 = "abc".compareTo("cba");
System.out.println(res3);

int res4 = "abc".compareTo("aba");
System.out.println(res4);
}
}

contains()

判断是否包含字符串

1
2
3
4
5
6
7
public class _432_String类的contains方法 {
public static void main(String[] args) {
// 判断是否包含字符串
System.out.println("hello".contains("ell"));
}
}

endsWith()

判断当前字符串是否以某字符串结尾

1
2
3
4
5
6
7
public class _433_String类的endsWith方法 {
public static void main(String[] args) {
// 判断当前字符串是否以某字符串结尾
System.out.println("t1.txt".endsWith(".txt"));
}
}

equals()和compareTo()

在Java8中equals()代码中不包含compareTo()…

equalsIgnoreCase()

就是忽略大小写的equals()

1
2
3
4
5
6
public class _437_String类的equalsIgnoreCase方法 {
public static void main(String[] args) {
System.out.println("abc".equalsIgnoreCase("ABC"));
}
}

getBytes()

就是将字符串转换为byte数组

1
2
3
4
5
6
7
8
9
public class _438_String类的getBytes方法 {
public static void main(String[] args) {
byte[] bytes = "ans".getBytes();
for (int i = 0; i < bytes.length; i++) {
System.out.println(bytes[i]);
}
}
}

indexOf()

返回字符串第一次出现起始位置的下标

1
2
3
4
5
6
7
8
public class _438_String类的getBytes方法 {
public static void main(String[] args) {

System.out.println("abcabcac".indexOf("ca")); // 2

}
}

isEmpty()

判断是否为空串
不能 String s = null 会空指针异常

1
2
3
4
5
6
7
8
9
public class _439_String类的isEmpty方法 {
public static void main(String[] args) {
String s = "";
System.out.println(s.isEmpty());
String s1 = "11";
System.out.println(s1.isEmpty());
}
}

lastIndexOf()

返回字符串最后一次出现的索引

1
2
3
4
5
6
public class _440_String类的replace方法 {
public static void main(String[] args) {
System.out.println("abcabcac".lastIndexOf("ca")); // 5
}
}

replace()

将“ab”->“xx”

1
2
3
4
5
6
7
8
public class _440_String类的replace方法 {
public static void main(String[] args) {
System.out.println("abaabc".replace("ab","xx"));


}
}

split()

拆分…

1
2
3
4
5
6
7
8
9
10
public class _440_String类的replace方法 {
public static void main(String[] args) {
String[] s = "2001-1-24".split("-");
for (int i = 0; i < s.length; i++) {
System.out.println(s[i]);
}
}
}


startsWith()

判断是否为某字符串开头

1
2
3
4
5
6
public class _441_String类的substring方法 {
public static void main(String[] args) {
System.out.println("abc".startsWith("ab"));
}
}

substring()

截取子字符串

1
2
3
4
5
6
7
8
9
public class _441_String类的substring方法 {
public static void main(String[] args) {
String s = "abcde".substring(3);
System.out.println(s); // "de"
String s1 = "abcde".substring(2,4);
System.out.println(s1); // 范围 [2,4) -> cd
}
}

toCharArray()

转化为char数组

1
2
3
4
5
6
7
8
9
public class _442_String类的toCharArray方法 {
public static void main(String[] args) {
char[] chars = "abc".toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
}
}

toLowerCase() 与 toUpperCase()

大小写转化

1
2
3
4
5
6
7
public class _443_String类的toLowerCase方法 {
public static void main(String[] args) {
System.out.println("ABC".toLowerCase());
System.out.println("abc".toUpperCase());
}
}

trim()

取出字符串前后空白

1
2
3
4
5
6
public class _444_String类的valueOf方法 {
public static void main(String[] args) {
System.out.println(" abc ".trim());
}
}

valueOf()

String类方法中 只有一个 valueOf 方法是静态的 不需要 new 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class _444_String类的valueOf方法 {
public static void main(String[] args) {
// String类方法中 只有一个 valueOf 方法是静态的 不需要 new 对象
String s = String.valueOf(97);
System.out.println(s); // "97" 现在已经是字符串了

String s1 = String.valueOf(new Customer());
System.out.println(s1); // 这里调用 Customer 的 toString 方法
}
}

class Customer{

}

StringBuffer

使用“+”进行字符串拼接,如String s = “a”+“b”,会在方法去产生两个字符串对象,在堆内存中产生一个String s对象,频繁使用导致内存空间的浪费

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class _445_StringBuffer进行字符串拼接 {
public static void main(String[] args) {
// 这样会给内存池很大压力
String s1 = "";
for (int i = 0; i < 100; i++) {
s1 += i;
}

// 使用 StringBuffer
// 初始化创建容量为16个bytes[]数组
StringBuffer s2 = new StringBuffer();
s2.append("a");
s2.append(3.14);
s2.append(true);
System.out.println(s2);

// 使用 StringBuffer 时最好创建时初始化初始容量,减少扩容次数
StringBuffer s3 = new StringBuffer(10);
s3.append("heooolo");
System.out.println(s3); // heooolo
s3.append("xxxxxxxx");
System.out.println(s3); // heoooloxxxxxxxx

}
}


StringBuilder和StringBuffer的区别

StringBuffer中的方法都有:synchronized 关键词修饰,表示StringBuffer在多线程环境下时安全的
StringBuilder是非线程安全的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class _446_StringBuilderStringBuffer的区别 {
public static void main(String[] args) {
// 代码没啥区别
StringBuilder s1 = new StringBuilder();
s1.append("abc");
s1.append(true);
s1.append(3.456);
System.out.println(s1);



}
}

Prev
2022-01-23 13:57:00 # JavaSE
Next