一、String
1.基本方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 1)length():String中字符的个数。 2 3 2)charAt(int index):取得String中该索引位置上的char。 4 5 3)toCharArray():生成一个char[],包含String的所有字符。 6 7 4)equals():比较两个String的内容是否相同。 8 9 5)compareTo(String anotherString):按词典顺序比较String的内容,比较结果为负数、零或正数。 10 11 6)contains(CharSequence s):如果该String对象包含参数的内容,则返回true。 12 13 7)equalsIgnoreCase():忽略大小写,如果两个String的内容相同,则返回true。 14 15 8)startsWith():返回boolean结果,以表明该String是否以此参数起始。 16 17 9)endsWith(String s):返回boolean结果,以表明此参数是否是该字符串的后缀。 18 19 10)isEmpty():当且仅当length()为0时返回true。 20 21 11)split(String regex):根据给定正则表达式的匹配拆分此字符串。 22 23 或|,点.,加+,乘*,在字符串中出现时,如果这个字符串需要被split,则split时候,需要在前面加两个反斜杠。 24 25 与&,在split时候,不需要转义。 26 27 12)substring(int beginIndex, int endIndex):返回一个新字符串,它是此字符串的一个子字符串。 28 29 13)toLowerCase():转为小写。 30 31 14)toUpperCase():转为大写。 32 33 15)trim():返回字符串的副本,忽略前导空白和尾部空白。 34 35 16)valueOf(char[] data):返回char数组参数的字符串表示形式。
2.不可变性
java中的不可变类:
1. 可变类和不可变类(Mutable and Immutable Objects)的初步定义:
可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容。
不可变类:当你获得这个类的一个实例引用时,你不可以改变这个实例的内容。不可变类的实例一但创建,其内在成员变量的值就不能被修改。
举个例子:String和StringBuilder,String是immutable的,每次对于String对象的修改都将产生一个新的String对象,而原来的对象保持不变,而StringBuilder是mutable,因为每次对于它的对象的修改都作用于该对象本身,并没有产生新的对象。
String对象是不可变的。也就是说可以给一个String对象加任意多的别名。因为String对象具有只读特性,所以指向它的任何引用都不可能改变它的值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Immutable { 2 public static String upcase(String s) { 3 return s.toUpperCase(); 4 } 5 public static void main(String[] args) { 6 String q = "howdy"; 7 print(q); 8 String qq = upcase(q); 9 print(qq); 10 print(q); 11 } 12 } 13 //结果:howdy HOWDY howdy
上述代码的解释:当把q传给upcase()方法时,实际传递的是引用的一个拷贝,这个引用所指的对象一直待在某个物理位置上。而对于upcase()的定义,传入其中的引用有了名字s,只有upcase()运行的时候,局部引用s才存在,一旦upcase()运行结束,s就消失了。而upcase()的返回值,其实只是最终结果的引用。而原本的q还在原地。
因为String的不可变性,所对string字符串做的所有的变更字符串的操作,都会导致new的产生,这样也就改变了upcase传进去的string的地址,所以原q是没有任何变化的。
通过反射改变String对象:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //创建字符串"Hello World", 并赋给引用s 2 String s = "Hello World"; 3 System.out.println("s = " + s); //Hello World 4 5 //获取String类中的value字段 6 Field valueFieldOfString = String.class.getDeclaredField("value"); 7 //改变value属性的访问权限 8 valueFieldOfString.setAccessible(true); 9 10 //获取s对象上的value属性的值 11 char[] value = (char[]) valueFieldOfString.get(s); 12 //改变value所引用的数组中的第5个字符 13 value[5] = '_'; 14 System.out.println("s = " + s); //Hello_World
3.重载的“+”操作符
不可变行带来一定的效率问题。而Java仅对"+"和"+="两个操作符重载过,且Java不允许程序员重载任何操作符。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Main { 2 public static void main(String[] args) { 3 String mango = "mango"; 4 String s = "abc" + mango + "def" + 47; 5 print(s); 6 } 7 } 8 //结果:abcmangodef47
在s = "abc" + mango + "def" + 47;的语法中,编译器自动创建了一个StringBuilder对象,用以构造最终的String,并为每个字符串调用一次StringBuilder的append()方法,总计4次。最后调用toString()生成结果,并存为s。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Test { 2 public String implicit(String[] fields) { 3 String result = ""; 4 for(int i = 0; i < fields.length; i++) { 5 result += fields[i]; 6 } 7 return result; 8 } 9 public String explicit(String[] fields) { 10 StringBuilder result = new StringBuilder(); 11 for(int i = 0; i < fields.length; i++) { 12 result.append(fields[i]); 13 } 14 return result.toString(); 15 } 16 }
implicit()方法:每循环一次,会创建一个新的StringBuilder对象,而每循环一次,之前创建的StringBuilder对象就会被gc回收。
explicit()方法:只生成一个StringBuilder对象。
4.new String("abc")创建几个对象
如果常量池中原来有“abc”,则只创建一个对象;否则创建两个对象。
总结:需要经常改变内容的字符串最好不要用String,因为每次生成对象都会对系统新能产生影响,特别当内存中无引用对象多了以后,GC就会开始工作,会拖慢速度。
适用于:少量的字符串操作的情况。
二、StringBuilder:是非线程安全的
适用于:单线程下在对字符串进行大量操作的情况
三、StringBuffer:是线程安全的
适用于:多线程下对字符串进行大量操作的情况。
三者运行效率的一般情况:StringBuilder>StringBuffer>String
特殊情况:
String str="abc"+"de";//更快 StringBuilder stringBuilder=new StringBuilder().append("abc").append("de");
这里的str会比stringBuilder快,因为str的赋值操作相当于str = "abcde",之所以会这样是因为有字符串常量池的存在。
而如果写成下面的形式,string依旧很慢:
String str1="abc";
String str=str1+"de";
因为会导致新对象的产生。
从存取上来说,String>StringBuffer
从多次改编上来说,StringBuffer>String