String类
- 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 类实现了接口 Serializable 【String 可以串行化:可以在网络中传输 】,也实现 接口Comparable 【String 对象可以比较大小】
- String 是final类,不能被其他类继承。
- String 有属性 private final char value[];用于存放字符串内容。
- 一定注意:value 是一个fianl类型,不可修改(不是字符内容不可修改,是存放地址不可修改)
创建String对象的两种方式
- 方式一:直接赋值String s="nihao";
- 方式二:调用构造器String s=new String("nihao");
区别:
- 方式一:先从常量池查看是否有"nihao"的数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。
- 方式二:先在堆中创建空间,里面维护了value属性,指向常量池的"nihao"空间。如果常量池中没有"nihao",重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
字符串特性
-
String是一个final类,代表不可变的字符序列
-
字符串是不变的。一个字符串对象一旦被分配,其内容是不可变的。
package com.study.srv.demo11;
/**
* @author Wen先森
* @version 1.0
* @date 2022/3/10 10:12
*/
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 | 转换为字符数组 |
valueOf | 将其他类型转换为字符串 |
format | 格式化字符串 |
String.valueOf()方法
由基本数据型态转换成String:
- String.valueOf(boolean b) : 将 boolean 变量 b 转换成字符串
- String.valueOf(char c) : 将 char 变量 c 转换成字符串
- String.valueOf(char[] data) : 将 char 数组 data 转换成字符串
- String.valueOf(char[] data, int offset, int count) : 将 char 数组 data 中 由 data[offset] 开始取 count 个元素 转换成字符串
- String.valueOf(double d) : 将 double 变量 d 转换成字符串
- String.valueOf(float f) : 将 float 变量 f 转换成字符串
- String.valueOf(int i) : 将 int 变量 i 转换成字符串
- String.valueOf(long l) : 将 long 变量 l 转换成字符串
- String.valueOf(Object obj) : 将 obj 对象转换成 字符串, 等于 obj.toString()
由 String 转换成 数字的基本数据型态 :
要将 String 转换成基本数据型态转 ,大多需要使用基本数据型态的包装类别 。
- byte : Byte.parseByte(String s) : 将 s 转换成 byte类型。
- Byte.parseByte(String s, int radix) : 以 radix是进制数 将 s 转换为 byte ,比如说 Byte.parseByte("11", 16) 就代表是16进制的"11",也就是17。
- double : Double.parseDouble(String s) : 将 s 转换成 double 。
- float : Double.parseFloat(String s) : 将 s 转换成 float 。
- int : Integer.parseInt(String s) : 将 s 转换成 int 。
- long : Long.parseLong(String s)。
StringBuffer类
- java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。
- 很多方法与Sting相同,但StringBuffer是可变长度。
- StringBuffer是一个容器。
package com.study.srv.demo11;
/**
* @author Wen先森
* @version 1.0
* @date 2022/3/11 11:52
*/
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 = new StringBuffer("hello");
StringBuffer转换
package com.study.srv.demo11;
/**
* @author Wen先森
* @version 1.0
* @date 2022/3/11 16:01
*/
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 |
reverse() | 字符串翻转 |
indexOf | 查找子串在字符串第一次出现的索引,如果找不到返回-1 |
insert | 插入 |
length | 获取长度 |
package com.study.srv.demo11;
/**
* @author Wen先森
* @version 1.0
* @date 2022/3/11 17:01
*/
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);
//删除
/**
* 删除索引为>=start&&<end处的字符
*/
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;
/**
* @author Wen先森
* @version 1.0
* @date 2022/3/14 11:04
*/
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;
/**
* @author Wen先森
* @version 1.0
* @date 2022/3/14 11:53
*/
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。