String、StringBuffer与StringBuilder

String

String简介

java中String为引用数据类型,其本身也为一个class文件,实现原理为char类型数组。(看下图)由于String类为final修饰的并且数组char value[]也为final修饰,所以String为不可变类型,赋值后不能改变,为字符串常量

String

举个栗子🌰

1
2
String a = "eli";
String a = "chen";

以上语句看似字符串a发生了改变,从eli变为chen,但是String不可变所说的为字符串本身不可变,不是其引用所指向的对象地址。这里创建了一个新的String对象并使用a引用指向其地址,原来的eli并没有发生改变而是失去了地址引用,变成了内存中的垃圾。

String之间的比较

我们在比较字符串时我们想比较的是字符串的内容是否相等,因为String为引用数据类型,String对象存储的只是指向该字符串堆空间的一个内存地址,使用==比较并不能得到正确结果,这与我们的初衷违背,因为String重写了Object类的equals()方法,我们在进行字符串比较式必须使用equals()方法,不能使用==代码演示

1
2
3
4
5
6
7
8
9
10
11
12
代码段1
String str1 = "aa";
String str2 = "aa";
System.out.println(str1 == str2); //true
System.out.println(str1.equals(str2)); //true
代码段2
String str3 = new String("cc");
String str4 = new String("cc");
System.out.println(str3 == str4); //false
System.out.println(str3.equals(str4)); //true
代码段3
String e = "eli" + "chen";

看以上代码发现str1==str2truestr3==str4false,原因是因为java在编译期会将相同的字符串当做一个对象放入常量池,所以str1str2为同一个对象,==也为true。使用new String()来创建对象会强制创建两个不同的对象,所以str3==str4false

以上代码共创建几个对象?

  • 代码段1:
    String str1 = “aa”;在字符串常量池创建一个对象”aa”,后面str2时直接引用该对象,不用再创建,共创建一个对象

  • 代码段2:
    先在字符串常量池创建一个对象”cc”,然后在堆空间创建两个对象,使str3和str4分别指向它们,共创建3个对象

  • 代码段3:
    在字符串常量区创建3个对象,分别是”eli” ,“chen”,“elichen”

    方法简介

判断功能

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
33
34
//1 equals判断字符串内容是否相等    引用数据类型  ==比较的是内存地址(是不是同一个对象)
String s1 = "aaa";
String s2 = new String("aaa");
System.out.println(s1.equals(s2));
//常量和变量使用equals比较内容时,尽量把常量写在前面

//equalsIgnoreCase 忽略大小写的比较
String str1 = "aaa";
String str2 = "AAA";
System.out.println(str1.equals(str2));
System.out.println(str1.equalsIgnoreCase(str2));

//contains 判断字符串是否包含某内容(子串)
String str = "abcde";
System.out.println(str.contains("ab"));
System.out.println(str.contains("cde"));
System.out.println(str.contains("ac"));

// startsWith endsWith 判断字符串是否以某个值开头 是否以某个值结尾
String str="http://www.sina.com.cn";
System.out.println(str.startsWith("h"));
System.out.println(str.startsWith("http"));
System.out.println(str.endsWith("cn"));
System.out.println(str.endsWith(".cn"));

// isEmpty 判断字符串是否 为空串
String str1 = "";
String str2 = new String();
String str3 = new String("");
String str4 = " ";
System.out.println(str1.isEmpty());
System.out.println(str2.isEmpty());
System.out.println(str3.isEmpty());
System.out.println(str4.isEmpty());

获取功能

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
33
34
35
// 1 length()  获取字符串长度(由多少个字符组成)
String str = "abc";
int x = str.length();
System.out.println(x);

//2 charAt 获取某个位置上的字符
String str = "abcde";
char c = str.charAt(1);
System.out.println(c);

//3 substring 截取子串
String str = "abcdefg";
String result = str.substring(2); //取到最后
System.out.println(result);
String result2 = str.substring(2,4); // 左闭右开
System.out.println(result2);

//4 indexOf 查找位置
String str = "abcdeabcd";
int idx = str.indexOf("cd");
System.out.println(idx);
int idx2 = str.indexOf("ab",3);
//int idx2 = str.indexOf("ab",-3);// 第2个参数为负数,相当于0
System.out.println(idx2);
int idx3 = str.indexOf("xy");
System.out.println(idx3); // 找不到时,返回-1

//5 lastIndexOf 查找位置 从后向前找
String str = "abcdeabcd";
int idx = str.lastIndexOf("cd");
System.out.println(idx);
int idx2 = str.lastIndexOf("ab",3);
System.out.println(idx2);
int idx3 = str.lastIndexOf("xy");
System.out.println(idx3); // 找不到时,返回-1

转换功能

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
33
34
35
36
37
// 1 getBytes()  将字符串转换成字节数组
String str = "abcd";
byte[] b = str.getBytes();
for(byte bb:b){
System.out.println(bb);
}

// 2 toCharArray() 将字符串转成字符数组
String str = "abcd";
char[] cc = str.toCharArray();
for(char c:cc){
System.out.println(c);
}

// 3 toUpperCase 小写转大写
String str = "abcd";
String str2 = str.toUpperCase();
System.out.println(str2);

//4 toLowerCase 大写转小写
String str = "AbCd";
String str2 = str.toLowerCase();
System.out.println(str2);

//5 concat 用来拼接字符串 和 +的作用相同 . 不同点: + 可以加任何类型 而concat只能拼接字符串
String s1 = "aaa";
String s2 = "bbb";
String s3= s1.concat(s2);
System.out.println(s3);

//6 valueOf 将其他类型转换成字符串 静态方法
int x = 100;
String str = String.valueOf(x);
System.out.println(str+1); // "1001"
int y = 200;
String str2 = y+""; //任何类型和字符串相加结果都是字符串
System.out.println(str2+1); //"2001"

StringBuffer(JDK1.0)

StringBuffer简介

StringBuffer为可变长字符串,原理与字符串相同,数组为可变长数组,默认容量为16,创建更长的字符串可以自动扩容。StringBuffer对象可以被多次修改并不会产生新的对象,进行字符串处理效率高。StringBuffer的方法都是使用synchronized修饰的方法,所以StringBuffer为线程安全的。

StringBuffer

StringBuffer方法简介

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
33
34
35
36
37
//StringBuffer构造方法1
StringBuffer sb1=new StringBuffer("Hello");
System.out.println(sb1);

String s1="World";
//StringBuffer构造方法2
StringBuffer sb2=new StringBuffer(s1);
System.out.println(sb2);

//length()返回字符串的长度
System.out.println(sb2.length());
//toString()这个方法重写了Object中的toString()方法,返回String类型的字符串
//输出StringBuffer对象时候,会默认调用此方法
System.out.println(sb2);

//append(String s)方法在原有的字符串后面添加字符串,返回的是添加后的StringBuffer对象
sb1.append(" World");
System.out.println(sb1);

//public StringBuffer deleteCharAt(int index)
//该方法的作用是删除指定位置的字符,然后将剩余的内容形成新的字符串
sb1.deleteCharAt(0);
System.out.println(sb1);//ello World

//public StringBuffer delete(int start,int end)
//从字符缓冲区中从start索引删除到end索引所对应的字符,其中包括start索引不包括end索引对应的值
sb1.delete(1, 3);
System.out.println(sb1);

//public StringBuffer insert(int offset,String str)
//在字符串缓冲区的第offset个字符后面插入指定字符串
sb1.insert(1, "ME");
System.out.println(sb1);

//public StringBuffer reverse(),将字符串反转
sb1.reverse();
System.out.println(sb1);

StringBuilder(JDK1.5)

StringBuilder简介

StringBuilder在JDK5.0新增的,StringBuilder与StringBuffer基本相同只不过不是线程安全的,方法也大致相同。StringBuilder效率更高。

总结

执行速度

  • 三者在执行速度方面的比较:StringBuilder > StringBuffer > String

    线程安全

  • StringBuffer:线程安全的,StringBuilder:非线程安全的

    使用策略

  • 1.如果要操作少量的数据用String
  • 2.单线程操作字符串缓冲区 下操作大量数据用StringBuilder
  • 3.多线程操作字符串缓冲区 下操作大量数据用StringBuffer
  • 4.不要使用String类的”+”来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类