String
一、创建string对象
- 字符串的字符使用Unicode编码,一个字符占两个字节
- 常用构造器:
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 s5 = new String(byte[] b);
- String类实现了接口Serializable,String可以串行化,在网络中传输;
实现了接口Comparable,String对象可以比大小 - String是final类,不能被其他的类继承
String源码:有属性private final char value[]; 用于存放字符串内容
value是一个final类型,不可以修改,即不能指向新的地址,但单个字符可以改变 - 创建String对象的两种方式
- 直接赋值 String s = “saa”;
- 调用构造器 String s = new String(“aaaa”);
- 区别
- 直接赋值先从常量池查看是否有”saa”数据空间,如果有,直接指向;如果没有,则重新创建,然后指向。s最终指向的是常量池的空间地址
- 先在堆中创建空间,里面维护value属性,指向常量池的"aaaa"空间,如果没有,重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址
- 字符串是不可变的,一个字符串对象一旦被分配,其内容是不可改变的
String s1 = “hello”;
s1 = “hhh”;
- String + 优化,判断创建的常量池对象,是否有引用指向
String a = “hello”+”abc” <=> String a = “helloabc” 只创建了一个对象 - String a = “hello”;
String b = “hhh”;
String c = a + b;
综上,常量相加,是在常量池中,变量相加,是在堆中- 先创建一个StringBuilder sb = StringBuilder()
- 执行 sb.append(“hello”)
- sb.append(“hhh”)
- String c = sb.toString() 这个方法中new了一个对象
c实际指向堆中的对象,堆中的对象指向池中的”hellohhh”
二、方法
String类保存字符串常量,每次更新都需要重新开辟空间,效率低
public class String01 {
public static void main(String[] args) {
// 1. equals 比较内容是否相同(区分大小写)
String str1 = "hello";
String str2 = "Hello";
System.out.println(str1.equals(str2)); // false
// 2. equalsIgnoreCase 忽略大小写判断内容是否相等
System.out.println(str1.equalsIgnoreCase(str2)); // true
// 3. length 获取字符的个数,字符串的长度
System.out.println(str1.length()); // 5
// 4. indexOf获取字符在字符串对象中第一次出现的索引,从0开始,找不到,返回-1
System.out.println(str1.indexOf('e')); // 1
// 5. lastIndexOf 获取字符在字符串中最后一次出现的索引,索引从 0 开始,如果找不到,返回-1
System.out.println(str1.lastIndexOf('l')); // 3
System.out.println(str1.lastIndexOf("ll")); // 2
// 6. subString 截取指定范围字符串
System.out.println(str1.substring(2)); // llo 索引2开始后面的
System.out.println(str1.substring(1,3)); // el 从索引1开始截取,截取到索引3-1 = 2位置
// 7. toUpperCase 转换成大写
System.out.println(str2.toUpperCase()); //HELLO
// 8. toLowerCase 转换成小写
System.out.println(str2.toLowerCase()); // hello
// 9. concat 拼接字符串
System.out.println(str1.concat("aaa").concat("2333")); // helloaaa2333
// 10. replace 替换字符串中的字符
System.out.println(str1.replace("ll","qq") +" "+ str1); // heqqo
System.out.println(str1); // hello replace返回的结果是替换过的
// 11. split 分割字符串
String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
String[] split = poem.split(","); // 按,分割
String path = "C:\\aaa\\vvv";
split = path.split("\\\\");
// 12. toCharArray转换成字符数组
char[] chars = str1.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
// 13. compareTo 比较两个字符串的大小,前者大返回正数,后者大返回负数,相等返回0
/*
(1) 长度相同,并且每个字符也相同,返回0
(2) 长度相同或者不同,但在进行比较时,可以区分大小 c1-c2
(3) 前面的部分都相同,返回str1.len-str2.len
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
*/
String a = "abc";
String b = "adc";
System.out.println(a.compareTo(b));
// 14. format格式字符串 占位符 %s %d %.2f %c
String name = "lll";
int age = 20;
double score = 98.3;
char g = '是';
String formatStr = "我的姓名是%s 年龄是%d,成绩是%.2f 是%c";
String info = String.format(formatStr,name,age,score,g);
System.out.println(info); // 我的姓名是lll 年龄是20,成绩是98.30 是是
}
}
三、StringBuffer类
- 基本介绍
StringBuffer代表可变的字符序列,可以对字符串内容进行增删,是一个容器
StringBuffer是final类,实现了Serializable,可以串行化,继承了抽象类AbstractStringBuilder,有属性char[] value,在堆中,不是final
StringBuffer字符内容是存在char[] value,在增加或删除时不用每次更换地址,创建新的对象,效率高于String
StringBuffer stringBuffer = new StringBuffer("hello");
和String相互转换
public class StringAndStringBuffer {
public static void main(String[] args) {
// String->StringBuffer
String str = "hello world";
// 方式1 构造器 返回的是StringBuffer对象,对str本身没有影响
StringBuffer stringBuffer = new StringBuffer(str);
// 方式2 append方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);
// StringBuffer->String
StringBuffer stringBuffer2 = new StringBuffer("hello");
// 方式1 使用StringBuffer提供的toString方法
String s = stringBuffer2.toString();
// 方式2 使用构造器
String s1 = new String(stringBuffer2);
}
}
StringBuffer类常见方法
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("hello");
// 增
s.append(','); // hello,
s.append("world"); // hello,world
s.append(100).append(true).append(15.23); // hlelo,world100true15.23
// 删
// 删除索引为>=start <end处的字符
s.delete(11, 14); // hello,worldtrue15.23 删除[11,14)的字符
// 改
s.replace(9, 11, "改的"); // hello,wor改的true15.23 替换索引[9,11)的字符
// 查找指定的子串在字符串第一次出现的索引,找不到返回-1
int indexOf = s.indexOf("改的");
System.out.println(indexOf); // 9
// 插入
s.insert(9,"插入"); // 在索引9位置插入,原来索引为9内容自动后移
System.out.println(s); // hello,wor插入改的true15.23
// 长度
System.out.println(s.length()); // 22
}
}
四、StringBuilder类
- 基本介绍
可变的字符序列,提供一个与StringBuffer兼容的API,但不保证线程安全,用在字符串缓冲区被单个线程使用的时候,大多数情况比StringBuilder快
主要是append和insert方法,可以重载以接受任意类型的数据
- 常用方法
StringBuilder是final类,实现了Serializable,可以序列化,继承了抽象类AbstractStringBuilder,有属性char[] value
StringBuilder stringBuilder = new StringBuilder();
五、String、StringBuffer 和 StringBuilder 的比较
效率:StringBuilder > StringBuffer > String
如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder
如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
字符串很少修改,被多个对象引用,使用String