存储
方式
- 直接赋值的方式会先去字符串常量池中查找是否已经有此值,如果有则把引用地址直接指向此值,否则会先在常量池中创建,然后,然后再把引用指向此值
- new String() 的方式一定会先在堆上创建一个字符串对象,然后再去常量池中查询此字符串的值是否已经存在,如果不存在会先在常量池中创建此字符串,然后把引用的值指向此字符串
- JDK 1.7 之后把永生代换成的元空间,把字符串常量池从方法区移到了 Java 堆上。
String s1 = new String("Java");
String s2 = s1.intern();
String s3 = "Java";
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // true
编译器还会对 String 字符串做一些优化
String s1 = "Ja" + "va";
String s2 = "Java";
System.out.println(s1 == s2);
代码 "Ja"+"va" 被直接编译成了 "Java" ,因此 s1==s2 的结果才是 true,这就是编译器对字符串优化的结果。
存储格式
JDK 1.8
char 数组
String str = "abc"; 等价 char data[] = {'a', 'b', 'c'}; String str = new String(data);
Java 9 之后
byte数组,这样做的好处是存储变的更紧凑,占用的内存更少,操作性能更高了。
方法
构造方法
String(byte[] bytes)
String(byte[] bytes, int offset, int length)
String(StringBuffer buffer)
String(StringBuilder builder)
2. 截取
subString
java 6 复用 堆中数组 bug
java 7创建新的
3. 拼接
3.1. +
- 字面量
- 转换为StringBuild
- 循环体外
3.2. public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements
3.3. StringJoiner
前缀 后缀,分隔符
String d="s";
StringJoiner stringJoiner = new StringJoiner(",","(",")");
stringJoiner.add("'23'");
stringJoiner.add("'22'");
System.out.println(stringJoiner.toString());
// ('23','22')
3.3.1. 为什么加
方便Stream 流
String collect = strings.stream().collect(Collectors.joining());
3.4. 可变字符串,不会产生新对象
- StringBuilder 线程不安全的
- StringBuffer
- 维护字符数组,会动态改变扩容 16
3.4.1. 删
sb.delete(0, 1);
sb.deleteCharAt(0);
3.4.2. 清空
sb.delete(0,sb.length());
sb.setLength(0);
3.4.3. 其他
StringBuffer sb = new StringBuffer();
StringBuffer sb1 = new StringBuffer(32);
sb.append(1).append(2).append(3456789);
System.out.println(sb.capacity());
// 至少但他还是会走动态扩充16*2+2=34
sb.ensureCapacity(25);
System.out.println(sb.capacity());
// 查
// 返回指定字符串(3)第一次出现的地方
int i = sb.indexOf("3");
// 从10索引开始找第一次3出现的地方
sb.indexOf("3", 10);
// 从右边算起和index类似
sb.lastIndexOf("12");
// 反转
sb.reverse().reverse();
// 替换
sb.replace(2, 5, "212");
System.out.println(sb);
// 去掉空格,节省内存
sb.trimToSize();
//
System.out.println(sb);
4. 删除空白字符
- trim():ASCII 小于32的任何字符
- strip():可以删除更多空白字符
- tic boolean isWhitespace(int codePoint)
- stripLeading
- stripTrailing
- replace
- \s+ 所有空白字符
- ^\s+ 开头
- \s+$ 结尾
5. 比较顺序
等于 0
小于 -1
大于 >0
- int compareTo(String anotherString) 按字典顺序比较两个字符串。
- int compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑大小写。
6. 索引-字符
- char charAt(int index) 返回指定索引处的 char 值。
- int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。
- int indexOf(int ch, int fromIndex) 返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
- int indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引。
- int indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
- String intern() native 方法,“如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回”
- boolean isEmpty() 当且仅当 length() 为 0 时返回 true。
- int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。
- int lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
- int lastIndexOf(String str) 返回指定子字符串在此字符串中最右边出现处的索引。
- int lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
7. 转码
- byte[] getBytes() 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
- byte[] getBytes(Charset charset) 使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
- void getBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin) 已过时。该方法无法将字符正确转换为字节。从 JDK 1.1 起,完成该转换的首选方法是通过 getBytes() 方法,该方法使用平台的默认字符集。
- byte[] getBytes(String charsetName) 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
8. 比较
- boolean equals(Object anObject) 将此字符串与指定的对象比较。
- boolean equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。
- boolean contains(CharSequence s) 当且仅当此字符串包含指定的 char 值序列时,返回 true。
- boolean contentEquals(CharSequence cs) 将此字符串与指定的 CharSequence 比较。
- boolean contentEquals(StringBuffer sb) 将此字符串与指定的 StringBuffer 比较。
- boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束。 boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开始
- boolean startsWith(String prefix, int toffset) 测试此字符串从指定索引开始的子字符串是否以指定前缀开始
- static String format(Locale l, String format, Object... args) 使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
- static String format(String format, Object... args) 使用指定的格式字符串和参数返回一个格式化字符串。
- int hashCode() 返回此字符串的哈希码。
- int length() 返回此字符串的长度。
- CharSequence subSequence(int beginIndex, int endIndex) 返回一个新的字符序列,它是此序列的一个子序列。
- String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。
- String substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。
9. 格式化
String str = null;
str = String.format("Hi, %s", "林志玲","");
System.out.println(str);
System.out.printf("3>7的结果是:%b %n", 3 > 7);
System.out.printf("100的一半是:%d %n", 100 / 2);
System.out.printf("50元的书打8.5折扣是:%f 元%n", 50 * 0.85);
System.out.printf("上面的折扣是%d%% %n", 85);
9.1. 日期
public void test3(){
Date data =new Data()
String str=String.format(Locale.US,"英文月份简称:%tb",date);
System.out.println(str);
System.out.printf("本地月份简称:%tb%n",date);
str=String.format(Locale.US,"英文月份全称:%tB",date);
System.out.println(str);
System.out.printf("本地月份全称:%tB%n",date);
str=String.format(Locale.US,"英文星期的简称:%ta",date);
System.out.println(str);
System.out.printf("本地星期的简称:%tA%n",date);
System.out.printf("年的前两位数字(不足两位前面补0):%tC%n",date);
System.out.printf("年的后两位数字(不足两位前面补0):%ty%n",date);
System.out.printf("一年中的天数(即年的第几天):%tj%n",date);
System.out.printf("两位数字的月份(不足两位前面补0):%tm%n",date);
System.out.printf("两位数字的日(不足两位前面补0):%td%n",date);
System.out.printf("月份的日(前面不补0):%te",date);
}