Thinking in java 之 String
String
- 在源码中 String被final修饰 因此String不能被继承
- String对象不可变,只要String对象被修改就会被创建新对象
- String对象可以被存到常量池,常量池中的对象可以被共享。
String a1 = "abc"; String a2 = "abc";
因为String对象存在常量池,所以a1,a2的地址相同 即a1 == a2 即a1,a2为同一块内存
jdk1.6之前,常量池为与方法区
jdk1.7 常量池位于堆中的一块内存
jdk1.8 从堆中挪出,挪到“元空间” metaspace 类似于方法区
String对象的存储:
- jdk1.9之前,底层用char[] 数组存储
- jdk1.9之后 ,用byte[]
cha[]由final修饰 因此String对象不能被更改
对象的比较
== 比较的是对象的地址
equals() 比较的也是对象地址但在String中被重写了,在String中比较的是字符串的内容
当字符串是常量时,即
String a1 = "abc";
String a2 = "abc";
a1 == a2;
当字符串用new时,存储在堆上,即
String a1 = new String("abc"); String a2 = new String("abc");
a1,a2地址不同

< > 比较
对象不能使用运算符
对象比较分两种:
- 自然排序 实现java.lang.Comparable接口.int compareTo(Object obj)
- 定制排序
对象的个数
String a1 = new String("abc");//两个对象
在常量池中有一个final修饰的char[]存储abc,在堆中有一个String对象,对象属性char[]指向常量池中的abc
String s1 = "hello"; String s2 = "hello"; final String s3 = "world"; String s4 = "helloworld"; String s5 = s1 + "world"; String s6 = s2 + s3; String s7 = "hello" + s3; String s8 = "hello" + "world"; System.out.println(s4 == s5);//false 变量+常量 为变量存储在堆中 System.out.println(s4 == s6);//false System.out.println(s4 == s7);//true 常量+常量 存储在常量池中 System.out.println(s4 == s8);//true
可变字符序列
- StringBuffer 线程安全
- StringBuilder :默认的char[]长度为16,长度不够的话,自动扩容为原来的2倍+2,即34. 线程不安全的
StringBuilder更快,当需要字符串拼接时,编译器会自动引入java.lang.StringBuilder类。
即使编译器会自动引入StringBuilder,也不能随意使用String对象 例如:
public String implicit(String[] fields){ String result = ""; for(int i = 0; i < fields.length; i++) result += fields[i]; return result; } public String explicit(String[] fields){ StringBuilder result = new StringBuilde(); for(int i = 0; i < fields.length; i++) result.append(fields[i]); return result.toString(); }
在implicit中,虽然系统会自动引入StringBuilder,但是在循环内,每循环一次就会创建一个StringBuilder ,而explicit中从始至终只有一个StringBuilder对象
因此如果为一个类编写toSting()时,如果字符串操作比较简单就可以信赖编译器,但如果要使用循环,那么最好创建一个StringBuilder对象。

浙公网安备 33010602011771号