1.String类
1.1.基本介绍
String类的对象用于保存字符串(一组字符序列) ,将字符序列用双引号括起来就是字符串常量,如:"abc","你好"- 字符串中的字符使用Unicode字符编码,一个字符不管是字母还是汉字,都占两个字节(char)
1.2.创建String类的对象
- 方式一: 直接赋值(字面量):
String s = "Java";
先从字符串常量池中查看是否有"java"的数据空间,如果有直接将value[]数组指向该数据空间的地址;如果没有则创建后指向;s -> value[] -> "java"在常量池中的地址
字符串常量池中不允许存放两个相同的字符串常量;
jdk7之前:字符串常量池在方法区中
jdk7及之后:字符串常量池在堆空间中
- 方式二:调用构造器:
//String类常用的构造方法(体现了方法的重载)
String s = new String();//String()
String s1 = new String("Hello");//String(String original)
char[] c = {'j','a','v','a'};
String s2 = new String(c); //String(char value[])
String s3 = new String(c, 0, 3);//String(char value[], int offset, int count)
输出后:
以String s = new String("Java");为例:
先在堆中创建空间,里面有String类用于存放字符串属性(value[]数组),s 指向 value[] 的地址;常量池中如果有"Java",则直接通过value[]指向其地址,没有则重新创建后再指向。
注意:s最终指向的是堆中value[] 的地址空间(区别与第一种方式)
1.3.String类细节
String类是final类,代表不可变的字符序列,不能被其他类继承
-
String类实际上是利用属性private final char value[]这个字符类型数组来存放字符串- jdk9之后,为了节省内存空间,使用
private final byte[] value作为存储字符串数据的容器
- jdk9之后,为了节省内存空间,使用
-
String类重写了equals方法,用于判断字符串内容是否相同 -
String类相加重要规则: 如果是常量相加,看的是常量池,如果是变量相加,则看的是堆。-
常量 + 常量 :结果仍在常量池;此时的常量可能是
final修饰常量 + 变量 / 变量 + 变量 :会在堆中new一个String对象返回其地址
调用
intern()方法返回字符串常量池中字面量的地址 -
执行代码
String s = "Hello" + "Java";时,编译器会判断创建的常量池对象是否有引用指向,所以只会创建一个"HelloJava"对象,"Hello"和"Java"对象会被丢弃 -
String变量相加如下面代码
-
String a = "Hello";
String b = "Java";
String c = a + b;
则会创建Hello、Java和HelloJava三个常量对象
- 不可变性的理解:
- 当对字符串变量重新赋值时,需要重新指定一个字符串常量的位置(新的常量池地址),不能在原有位置修改,原字符串常量仍存在
- 当对原有字符串进行拼接或者
replace()操作时,都需要重新开辟空间保存新的字符串,原有字符串不能修改
1.4.String类的常用方法
equals区分大小写判断内容是否相等equalsIgnoreCase忽略大小写判断内容是否相等length获取字符串的长度indexOf获取指定字符或子串在字符串中第一次出现的索引,找不到返回-1lastIndexOf获取指定字符在字符串中最后一次出现的索引,找不到返回-1substring截取指定范围的子串
public static void main(String[] args) {
String s = "Hello,Java~";
System.out.println(s.substring(5));//从索引5开始截取后面的所有内容
System.out.println(s.substring(0,5));//从索引0开始截取长度为5的子串
}
trim去除前后空格charAt获取指定索引处的字符toUpperCase转换成大写toLowerCase转换成小写concat拼接字符串replace替换字符串中的字符split根据指定的字符分割字符串(可以赋给一个数组)(分割时如果有特殊字符需加入转义字符)toCharArray转换成字符串数组compareTo逐位比较两字符串大小,前者大返回整数,后者大返回负数,相等返回零format格式化字符串
2.StringBuffer
2.1.基本介绍
StringBugger代表可变的字符序列,可以对字符串内容进行增删,很多方法和String类相同,但StringBuffer的长度是可变的。StringBuffer同时也是一个容器。
2.2.创建StringBuffer对象
//创建一个容量为16的字符串缓冲区(char[]数组)存放字符串
StringBuffer sb = new StringBuffer();
//将参数中的字符串存入缓冲区,容量为当前字符串长度加16
StringBuffer sb1= new StringBuffer("Java");
//创建指定容量大小的字符串缓冲区
StringBuffer sb2 = new StringBUffer(100);
2.3.StringBuffer细节
StringBuffer继承了父类AbstractStringBuffer的属性char[] value(不是final的),所以字符串中的内容是存放在堆中的(value指向堆中的字符数组地址)StringBuffer是一个final类,不能被继承- 扩容机制,默认创建新的容量为:原容量 * 2 + 2 的数组,将原有value数组中的元素复制到新数组
2.4.StringBuffer常用方法
append增加字符delete(start,end)按索引删除字符replace(start,end,string)用string替换索引范围的子串indexOf(string)查找子串在字符串第一次出现的索引,找不到返回-1insert(int,string)在索引处插入指定字符串length获取长度
2.5.String 对比 StringBuffer
String保存的是字符常量,里面的值不能更改,String类的对象每次更新都是更改地址(创建新对象) ,效率较低。StringBuffer保存的是字符串变量,里面的值可以更改,每次更新时可以直接改变值,不用更新地址。
2.6.String和StringBuffer的转换
String->StringBuffer
String str = "Java~";
//方式1 使用构造器
StringBuffer sb = new StringBuffer(str);
//方式2 使用append方法
StringBuffer sb1 = new StringBuffer();
sb1 = sb1.append(str);
StirngBuffer->String
StringBuffer sb2 = new StringBuffer("Java~");
//方式2 使用构造器
String s = new String(sb2);
//方式1 使用StringBuffer的toString方法
String s1 = sb2.toString();
3.StringBuilder
3.1.基本介绍
StringBuilder也是一个可变的字符序列,在字符串缓冲区被单个线程使用,可以作为一个简易的StringBuffer。大多情况下StringBuilder比StringBuffer快,所以建议优先使用StringBuilder。但此类有线程安全问题,使用时需注意。
3.2.StringBuilder主要方法
StringBuilder和StringBuffer方法是一样的。主要使用append和insert方法,可以重载这些方法用来接收任意类型的数据。
3.3.StringBuilder细节
StringBuilder是final类,不能被继承StringBuilder也继承了父类AbstractStringBuilder的属性char[] value来存放数据,所以字符序列也在堆中。StringBuilder的方法都没有做互斥的处理(synchronized关键字),所以在单线程的情况下才使用
4.三者对比
| String | 不可变字符序列 | 效率低,但是复用率高(一个字符串可以被无限使用) |
|---|---|---|
| StringBuffer | 可变字符序列 | 效率高,线程安全 |
| StringBuilder | 可变字符序列 | 效率最高,线程不安全 |
String类如果多次执行改变串内容的操作,会导致大量没有引用字符串对象留在常量池中,降低效率;所以要对字符串做大量修改时,使用StringBuilder(单线程时优先选择)和StringBuffer,不使用String- 在字符串对象无需频繁修改,被多个对象引用时,使用
String效率更高。