- String对象用于保存字符串,也就是一组字符序列字符串常量对象是用双引号括起的字符序列。例:"hello","3.1415926","年后"等。字符串的字符使用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)
- 方式一:直接赋值String s="nihao";方式二:调用构造器String s=new String("nihao");
区别:
- 方式一:先从常量池查看是否有"nihao"的数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。方式二:先在堆中创建空间,里面维护了value属性,指向常量池的"nihao"空间。如果常量池中没有"nihao",重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
String是一个final类,代表不可变的字符序列
字符串是不变的。一个字符串对象一旦被分配,其内容是不可变的。
package com.study.srv.demo11;
public class Demo05 {
public static void main(String[] args) {
String a="hello";
String b="abc";
String c=a+b;
String d=a+"abc";
//底层是StringBuilder sb=new StringBuilder(); sb.append(a);sb.append("abc"); sb是在堆中,并且append是在原来字符串的的基础上追加的。
//重要规则,String e="hello"+"abc";常量相加,看的是常量池。String d=a+"abc";变量相加,是在堆中。
String e="hello"+"abc";
String f="helloabc";
System.out.println(e==f);//说明 String e="hello"+"abc";会自动优化,等价于String f="helloabc";
System.out.println(c);
System.out.println(d);
System.out.println(c==d);
System.out.println(c==e);
System.out.println(d==e);
System.out.println(d==f);
}
}
String d 创建过程如下:
因此与String e="hello"+"abc";这种常量相加指向常量池的不同
String类的常见方法| 方法名 | 说明 |
| equals | 区分大小写,判断内容是否相等 |
| equalsgnoreCase | 忽略大小写的判断内容是否相等 |
| length | 获取字符的个数,字符的长度 |
| indexOf | 获取字符在字符串中第一次出现的索引,索引从0开始,如果找不到,返回-1 |
| lastIndexOf | 获取字符在字符串中最后一次出现的索引,索引从0开始,如果找不到,返回-1 |
| substring | 截取指定范围的子串 |
| trim | 去前后空格 |
| charAt | 获取某索引处的字符,注意不能使用Str[index]这种方式 |
| toUpperCase | 将小写字母转换为大写字母 |
| toLowerCase | 将大写字母转换为小写字母 |
| concat | 字符串拼接 |
| replace | 替换字符串中的字符 |
| spit | 分割字符串 |
| compareTo | 比较两个字符串大小,如果前者大,则返回正数;后者大,则返回负数;如果相等,则返回0 |
| toCharArray | 转换为字符数组 |
| format | 格式化字符串 |
java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。很多方法与Sting相同,但StringBuffer是可变长度。StringBuffer是一个容器。
package com.study.srv.demo11;
public class Demo09 {
public static void main(String[] args) {
//1.StringBuffer的直接父类就是 AbstractStringBuilder
//2.它也实现了java.io.Serializable接口 即StringBuffer的对象可以串行化
//3.在父类中 有属性char[] value;不是final类型,该value数组存放字符串内容
//4.StringBuffer是一个final类不能被继承。
StringBuffer stringBuffer = new StringBuffer();
}
}
String VS StringBuffer
- String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低 //private final char value[];StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用更新地址,效率较高// char[] value;
StringBuffer stringBuffer =new StringBuffer();
默认创建一个大小为16的char[],用于存放字符内容。实际上真正存放在父类的value里。
StringBuffer stringBuffer =new StringBuffe(100);
通过构造器指定char[]大小。
StringBuffer转换StringBuffer stringBuffer = new StringBuffer("hello");
package com.study.srv.demo11;
public class Demo10 {
public static void main(String[] args) {
//String 转换为StringBuffer
String str="hello world";
//方式一:使用构造器
//注意:返回的是StringBuffer对象,对str本身没有影响。
StringBuffer stringBuffer = new StringBuffer(str);
//方式二:使用的是append方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);
//StringBuffer转为String
StringBuffer stringBuffer2 = new StringBuffer("jack");
//方式一:使用StringBuffer提供的toString方法
String s=stringBuffer2.toString();
System.out.println(s);
//方式二:使用构造器搞定
String s1 = new String(stringBuffer2);
System.out.println(s1);
}
}
StringBuffer常用方法
| 方法名 | 说明 |
| append | 增加 |
| delete(start,end) | 删除 |
| replace(start,end,string) | 将start--end间的内容替换掉,不含end |
| indexOf | 查找子串在字符串第一次出现的索引,如果找不到返回-1 |
| insert | 插入 |
| length | 获取长度 |
package com.study.srv.demo11;
public class Demo11 {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("hello");
//增加
s.append(',');//"hello,"
s.append("java");//"hello,java"
s.append("app").append(100).append(true).append(3.14);//"hello,javaapp100true3.14"
System.out.println(s);
//删除
s.delete(5,9);//[5,9) 即删除5~9(不包含9)的索引下的字符
System.out.println(s);
//修改
s.replace(0,5,"world");
System.out.println(s);
//查找
//查找指定的字串在字符串第一次出现的索引,如果找不到,返回-1
int index=s.indexOf("a");
System.out.println(index);
//插入
s.insert(5,"武当张三丰太极剑法");//即在索引为5的地址插入"武当张三丰太极剑法"
System.out.println(s);
//长度
System.out.println(s.length());
System.out.println(s);
}
}
StringBuilder类
- 一个可变的字符序列。此类提供了一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer快。在StringBuffer上的主要操作类型是append和insert方法,可以重载这些方法,以接受任意类型的数据。
package com.study.srv.demo11;
public class Demo14 {
public static void main(String[] args) {
//1.StringBuilder继承了AbstractStringBuilder类
//2.实现了Serializable,说明StringBuilder对象也是可以串行化的(串行化即是:对象可以用于网络传输,也可以保存到文件中)
//3.StringBuilder是final类,不能被继承
//4.StringBuilder对象字符序列仍然存放在其父类AbstractStringBuilder的char[]value;
//因此,字符序列是存放到堆中
//5.StringBuilder的方法,没有做同步处理,即没有synchronized 关键字,因此在单线程的情况下使用。所以才会线程不安全。
StringBuilder stringBuilder = new StringBuilder();
}
}
为什么StringBuffer是线程安全的,而StringBuilder是线程不安全的?原因就在于synchronized关键字。
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
StringBuilder在append操作时并未使用线程同步,而StringBuffer几乎大部分方法都使用了synchronized关键字进行方法级别的同步处理。
String、StringBuffer和StringBuilder比较- StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样。String:不可变字符序列,效率低,但是复用率低。StringBuffer:可变字符序列,效率高(增删)、线程安全。StringBuilder:可变字符序列,效率最高,但是线程不安全。
String使用注意说明:
String s="a"; //创建了一个字符串
s+="b";//实际上原来的"a"字符串对象已经丢弃了,现在又产生一个字符串"ab"。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大的影响程序的性能。所以,如果我们对String做大量的修改,不要使用String一般使用StringBuffer,如果是单线程的话使用StringBuilder。
package com.study.srv.demo11;
public class Demo15 {
public static void main(String[] args) {
String s="";
long startDate=0;
long endDate=0;
StringBuffer sb = new StringBuffer();
StringBuilder sd = new StringBuilder();
startDate=System.currentTimeMillis();
for (int i=0;i<50000;i++){
s+=i;//String拼接
}
endDate=System.currentTimeMillis();
System.out.println("String执行时间为:"+(endDate-startDate));
startDate=System.currentTimeMillis();
for (int i=0;i<50000;i++){
sb.append(String.valueOf(i));//StringBuffer拼接
}
endDate=System.currentTimeMillis();
System.out.println("StringBuffer执行时间为:"+(endDate-startDate));
startDate=System.currentTimeMillis();
for (int i=0;i<50000;i++){
sd.append(String.valueOf(i));//StringBuilder拼接
}
endDate=System.currentTimeMillis();
System.out.println("StringBuilder执行时间为:"+(endDate-startDate));
}
}
String、StringBuffer、StringBuilder的选择
使用原则,结论:
如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder。如果字符串存在大量的修改操作,并且在单线程情况下,使用StringBuilder。如果字符串存在大量的修改操作,并且在单线程情况下,使用StringBuffer。如果字符串很少修改,被多个对象引用,使用String。



