字符串字面量在编译阶段就已经确定了将其放到字符串常量池中。JVM启动时会立即将程序中带有双引号的字符串全部放入字符串常量池
String 构造方法
- String(char[] value):根据字符串数组创建一个新的字符串对象
- String(char[] value, int offset, int count):根据字符数组的指定部分创建一个新的字符串
- String(byte[] bytes):根据字节数组创建一个新的字符串对象,默认平台默认的字符集进行解码
- String(byte[] bytes, int offset, int length):根据字节数组的指定部分创建一个新的字符串对象,默认使用平台默认的字符集进行解码
- String (byte[] bytes, Charset charset):根据字节数组和指定的字符集创建一个新的字符串对象
第二个参数:StandardCharsets.UTF_8,这种
- String (byte[] bytes, Char.defaultCharset():按照系统默认字符编码,创建新字符串对象
- String (byte[] bytes , String charsetName):根据字节数组和指定的字符编码名称创建一个新的字符串对象
- String (String original):通过赋值现有的字符串创建一个新的字符串对象
这个方法被 @IntrinsicCandidate 标注。这个注解的作用告诉编译器,该方法或构造方法是一个内在的候选方法,可以被优化和替换为高效的代码。因此不建议使用
涉及到 byte 数组的构造方法要注意,解码格式和编码格式的一致问题
String 底层
可以看到底层是一个 private final 属性的数组,说明 String 是不可修改的,这个是jdk 8 ,再往上版本就是 byte[] 数组了
String 堆区与常量区的问题
String a = new String("jjj")
这种 new 出来的会现在堆区建立空间, 里面维护底层的 value 数组,再指向常量区的字符串,a 指向这个堆区
图示:
String a = "jjj";
这种是直接指向常量区的这个字符串,如果常量区没有就创建一个。创建后,它就可以共享,下次再创建就直接指向它
图示
String a = "abc" + "de";
这种只在常量池创建一个 字符串常量,因为编译器优化了。把字符串合并成 "abcde "
String a = "abc";
String b = "de";
String c = a + b;
底层会创建一个 StringBuilder temp = new StringBuilder();
然后 执行 temp.append(“abc”), temp.append(“cd”);
最后 创建一个 String c 接收 temp。
相当于
StringBuilder temp = new StringBuilder();
temp.append("abc");
temp.append("cd");
String c = temp.toString();
temp.toString 注意!!!
可以看到 toString底层是 new 一个 String 所以,c最后是指向堆区的。就是刚开始讲的那一套
总结: 如果是 String 相加两边 都是 常量,那就编译器优化,放常量区,其他情况底层就用 StringBuilder,然后就是如果有 final 修饰的变量那就看成常量
Sring 常用方法
- equals:
区分大小写 比较内容是否相同,String 重写了 equals,可以追源码看看
String str1 = "hello";
String str2 = "hello";
System.out.println(str1.equals(str2)); //true
- equalsIgnoreCase
忽略大小写的判断内容是否相等
String a = "hello";
String b = "Hello";
System.out.println(a.equalsIgnoreCase(b)); //true
- indexof
获取字符或者字符串在字符串对象中第一次出现的索引,索引从 0 开始,如果找不到返回 -1
String s1 = "jjj#";
int index = s1.indexOf("#");
System.out.println(index);
- lastindexof
获取字符或字符串 在字符串中 最后一次出现的 索引,索引从 0 开始,如果找不到就返回 -1
String s1 = "jjj##";
int index = s1.lastIndexOf("#");//返回4
System.out.println(index);
- subString
截取指定范围的字符串
String s1 = "jjj##";
System.out.println(s1.substring(0)); //0 索引后面全部
System.out.println(s1.substring(0,2)); //左闭右开 [0,2),也就是 jj
- toUpperCase
转换成大写
System.out.println(s.toUpperCase());
- toLowerCase
转换成小写
String s = "HELLO";
System.out.println(s.toLowerCase());
- concat
拼接字符串
String s = "HELLO";
String s1 = "WORD";
String s2 = "KKK";
String s3 = s.concat(s1).concat(s2);
System.out.println(s3);
- replace
替换字符串中的字符
String s1 = "hello world";
String s2 = s1.replace("hello", "fuck") //s1还是没变
System.out.println(s2); //s1 中 的 hello 改成 fuck
s1.replace 方法执行后,返回的结果才是替换过的,相当于搞一个新的string ,原本的s1没变
- split
分割字符串,对于某些分割字符,我们需要转移 比如 | 等,指定一个符号为标准,对字符串进行分割
String test = "E:\\aaa\\bbb\\ccc";
String[] res = test.split("\\\\");//这里要转义 按照\\分割开存进 res
for(String i : res) {
System.out.println(i);
}
- toCharArray
转换成字符数组
String test = "she is sb";
char[] res = test.toCharArray();
for(char i : res) {
System.out.println(i);
}
- compareTo
比较两个字符串的大小,如果前者大,则返回正数,后者大,则返回负数,如果相等返回 0
String front = "Aa";
String last = "AB";
System.out.println(front.compareTo(last)); //这里两个字符串长度相等,先比较第一个字符,相等比较 第二个字符 用 第一个字符 减 第二个字符
String front = "jac";
String last = "jack";
System.out.println(front.compareTo(last)); //如果前面都相等,后面没了,直接 上面字符串长度 减掉 下面字符串长度
- format
格式化字符串
占位符有:
%s 字符串 %c 字符 %d 整型 %f浮点型, 和 c语言用法一样的
String name = "ikun";
int age= 10;
double score = 92.3 / 3;
char gender = '男';
String info = String.format("%s, %d, %.2f, %c", name, age, score, gender);
其他常用方法