一、String类
1. String类的介绍和创建对象
-
String对象用于保存字符串,也就是一组字符序列。
-
常量对象:字符串常量对象是用双引号括起的字符序列。例如:“你好”、“12.97”、"boy"等。
-
字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。
-
String类较常用构造器。
String s1 = new String(); String s2 = new String(String original); String s3 = new String(char[] a); String s4 = new String(char[] a,int startIndex,int count);
-
源码
2. 创建String对象的两种方式
方式一:直接赋值 String s1 = "hello";
方式二:调用构造器 String s2 = new String("hello");
3. 两种创建String对象的区别
3.1 方式一
- 先从常量池查看是否有“hello” 数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s1最终指向的是常量池的空间地址。
3.1 方式二
- 1)先在堆中创建空间,里面维护了value属性,指向常量池的hello空间。如果常量池没有“hello”,重新创建,如果有,直接通过value指向。s2最终指向的是堆中的空间地址。
3.3 测试
String a = new String("abc");
String b =new String("abc");
System.out.println(a.equals(b));//true
System.out.println(a==b); // false
String a = "abc";
String b =new String("abc");
System.out.println(a.equals(b)); //真
System.out.println(a==b); //假
System.out.println(a==b.intern());//真 intern 表示获取常量
System.out.println(b==b.intern()); // 假
知识点:
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用
解读:(1) b.intern() 方法最终返回的是常量池的地址(对象)。
String s1 = "hello";
String s2 = "java";
String s4 = "java";
String s3 = new String("java");
System.out.println(s2 == s3); //F 分析 s2指向常量池 s3指向堆
System.out.println(s2 == s4); //T s2 和 s4 指向常量池,并是同一个常量
System.out.println(s2.equals(s3));// 比较内容, 真
Person p1 = new Person();
p1.name = "hello";
Person p2 = new Person();
p2.name = "hello";
System.out.println(p1.name.equals(p2.name)); // 真,比较内容
System.out.println(p1.name == p2.name); // 真 p1.name 和 p2.name 指向常量池, 并是同一个常量
System.out.println(p1.name == "hello"); //真, p1.name 和 “hello” 常量池
String s1 = new String("bcde");
String s2 = new String("bcde");
System.out.println(s1==s2); // 假 s1 指向堆 s2指向堆, 不是同一个对象
4. 字符串的特性
4.1 介绍
- String是一个final类,代表不可变的字符序列。
- 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
4.2 面试题(1)
String a ="hello" + "abc"; 创建了几个对象?
// 只有一个对象 1个对象
分析:
- 编译器底层会做优化。
- String a =“hello” + “abc”; ==> String a = “helloabc”;
4.3 面试题(2)
String a = "hello";
String b = "abc";
String c = a + b;
创建了几个对象?
// 3个对象
分析:
-
变量相加时, a + b 时,底层使用的 StringBuilder, 内容在堆。
-
String c = a + b; 底层是 StringBuilder sb = new StringBuilder(a); sb.append(b); sb是在堆中,并且append是在原来字符串的基础上追加的。
-
规则:
String c1 = "ab" + "cd";常量相加,看的是池。String c1 = a + b; 变量相加,是在堆中。
4.3 面试题(3)
String s1 = "hello"; //s1 常量池
String s2 = "java"; // s2 常量池
String s5 = "hellojava"; // s5 常量池
String s6 = (s1 + s2).intern(); // s6 指向 常量池
System.out.println(s5 == s6); // T 【s5 和 s6 的内容相同,并且都指向池】
System.out.println(s5.equals(s6)); // T 【内容,相等的】
5. String类的常见方法
String类是保存字符串常量的,每次更新都需要重新开辟空间,效率较低,因此java设计者还提供了StringBuilder 和 StringBuffer 来增强String的功能,并提高效率。
方法 | 方法说明 |
---|---|
equals | 区分大小写,判断内容是否相等 |
equalsIgnoreCase | 忽略大小写的判断内容是否相等 |
length | 获取字符的个数,字符串的长度 |
indexOf | 获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1 |
lastIndexOf | 获取字符在字符串中最后1次出现的索引,索引从0开始,如果找不到,返回-1 |
substring | 截取指定范围的子串 |
trim | 去前后空格 |
charAt | 获取某索引处的字符,注意不能使用Str[index] 这种方式 |
toUpperCase | 转换成大写 |
toLowerCase | 转换成小写 |
concat | 拼接字符串 |
compareTo | 比较两个字符串的大小,如果前者大,则返回正数,后者大,则返回负数,如果相等,返回0 |
二、StringBuffer类
1. 介绍
-
java.lang.StringBuffer
代表可变的字符序列,可以对字符串内容进行增删。 -
很多方法与String相同,但StringBuffer是可变长度的。
-
StringBuffer是一个容器。
2. String和StringBuffer的对比
-
String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低。
private final char value[];
-
StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用更新地址,效率较高。
private transient char[] toStringCache; // 这个放在堆
3. StringBuffer的构造器
4. String和StringBuffer相互转换
4.1 String 转 StringBuffer
String s = "hello";
// 方式一
StringBuffer sb1 = new StringBuffer(s);
// 方式二
StringBuffer sb2 = new StringBuffer();
sb2.append(s);
4.2 StringBuffer 转 String
StringBuffer sb = new StringBuffer("hello");
// 方式一
String s1 = sb.toString();
// 方式二
String s2 = new String(sb);
5. StringBuffer类常见方法
方法 | 方法说明 |
---|---|
append | 增 |
delete(start,end) | 删 |
replace(start,end,string) | 改,start —— end 间的内容替换掉,不含end |
indexOf | 查,查找子串在字符串第1次出现的索引,如果找不到返回-1 |
insert | 插入 |
length | 获取长度 |
三、StringBuilder类
1. 介绍
- 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步【多并发+多线程】,1)该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
- 在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串生成器中。append 方法始终将这些字符添加到生成器的末端;而 insert 方法则在指定的点添加字符。
2. StringBuilder常用方法
StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和StringBuffer一样。
3. String、StringBuffer和StringBuilder的比较
-
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样.
-
String:不可变字符序列,效率低,但是复用率高。
-
StringBuffer:可变字符序列、效率较高(增删)、线程安全。
-
StringBuilder(JDK1.5):可变字符序列、效率最高、线程不安全(方法没有用synchronized关键字修饰)。
线程安全 | 适用场景 | 字符序列 | |
---|---|---|---|
String | 少量字符串操作的场景 | 不可变 | |
StringBuffer | 线程安全 | 多线程下在字符缓冲区进行大量操作的场景 | 可变 |
StringBuilder | 线程不安全 | 单线程下在字符缓冲区进行大量操作的场景 | 可变 |
运行速度快慢
StringBuilder > StringBuffer > String
----- |
| String | | 少量字符串操作的场景 | 不可变 |
| StringBuffer | 线程安全 | 多线程下在字符缓冲区进行大量操作的场景 | 可变 |
| StringBuilder | 线程不安全 | 单线程下在字符缓冲区进行大量操作的场景 | 可变 |
运行速度快慢
StringBuilder > StringBuffer > String