1 不可变String
String 对象是不可变的。String类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。
public class Immutable{
public static String upcase(String s){
return s.toUpperCase();
}
public static void main(String[] args){
String q = "hello";
System.out.println(q);
String qq = upcase(q);
System.out.println(qq);
System.out.println(q);
}
}
/*
运行结果:
hello
HELLO
hello
*/
当把q传给upcase()方法时,实际传递的是引用的一个拷贝。其实,每当把String对象作为方法的参数时,都会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置上,从未动过。
upcase()返回的引用已经指向了一个新的对象,而原本的q则还在原地。
2 重载“+”与StringBuilder
* String对象具有只读特性,所以指向它的任何引用都不可能改变它的值。*
不可变性会带来一定的效率问题。为String对象重载的“+”操作符就是一个例子。重载的意思是,一个操作符在应用于特定的类时,被赋予了特殊的意义(用于String的“+”与“+=”是Java中仅有的两个重载过的操作符)。
public class Concatenation{
public static void main(String[] args){
String mm = "mm";
String s = "1haha"+mm+"2ss"+55;
System.out.println(s);
}
}
/*
*执行javap -c Concatenation 反编译以上代码 生成JVM字节码
*/
/*
public class Concatenation {
public Concatenation();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String mm
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String 1haha
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)L
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)L
19: ldc #7 // String 2ss
21: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)L
24: bipush 55
26: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringB
29: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String
32: astore_2
33: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
36: aload_2
37: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return
}
*/
编译器自动引入了StringBuilder类。因为它更高效。显示地创建StringBuilder还允许你预先为其指定大小,可以避免多次重新分配缓冲。StringBuilder re = new StringBuilder()
当你为一个类编写toString()方法时,如果字符串操作比较简单,那就可以信赖编译器,它为你合理地构造最终的字符串结果(使用“+”)。但是,如果你要在toString() 方法中使用循环,那么最好自己创建一个StringBuilder对象,用它来构造最终的结果。
3 无意识的递归
public class InfiniteRecursion{
public String toString(){
return "address:"+this+"\n"; //打印出对象的内存地址 出现异常
// return super.toString(); 应该使用Object.toString()方法打印对象的地址。
}
}
这里发生了自动类型转换,由InfiniteRecursion类型转换成String类型。因为编译器看到一个String对象后面跟着一个”+“,而再后面的对象不是String,于是编译器试着将this转换成一个String——通过调用this上的toString()方法。于是就发生了递归调用(无法正常结束)。
4 String上的操作
//部分方法尝试,其余的大多数方法都能够通过名字判断其用意
public class StringMethodTest{
public static void main(String[] args){
String s = " hc hc ";
char[] aChars = new char[10];
print("展示各类方法结果:");
print("trim: "+s.trim());
print("getChars:");
s.getChars(1,5,aChars,2);
for(char aa : aChars){
System.out.print(aa);
}
System.out.println();
print("regionMatches: "+s.regionMatches(1," ha",0,2)); //部分匹配 该String的索引偏移量,另一个String及其索引偏移量,要比较的长度
print("replace: " +s.replace('c','h'));
print("valueOf: "+s.valueOf(3));
print("intern: "+s.intern());
}
public static void print(String s){
System.out.println(s);
}
}
/*展示各类方法结果:
trim: hc hc //只能删除两端的空白字符
getChars:
aa hc aaaa //自动填充a
regionMatches: true //部分匹配(应注意空白字符不能被忽略)
replace: hh hh
valueOf: 3 //返回一个表示参数内容的String
intern: hc hc
*/
当需要改变字符串的内容时,String类的方法都会返回一个新的String对象。同时,如果内容没有发生改变,String的方法只是返回指向原对象的引用而已。这可以节约存储空间以及避免额外的开销。
5 格式化输出
5.1 printf()
printf("Row 1: [%d %f]\n",x,y); //使用特殊的占位符(称为格式修饰符)来表示数据将来的位置,还可插入格式化字符串的参数。
在插入数据时,如果想要控制空格与对齐,需要更精细的格式修饰符 ,以下是其抽象语法:
%[argument_index$][flags][width][.precision]conversion
width 域的最小尺寸 默认数据是右对齐,可以是用"-"来改变对齐方向。
precision 最大尺寸 只能用于String和浮点数(默认是六位小数)。
举例:"%-10.5s" 占10个空格的位置,左对齐,只保留5个字符 String
String.format("%2$d + %5d",1,2); 返回的是2+ 1。
5.2 System.out.format()和String.format()
System.out.format()与printf()是等价的。String.format()返回一个String对象,内部也是创建了一个Formatter对象。
5.3 Formatter类
在Java中,所有新的格式化功能都由java.util.Formatter类处理。可以将Formatter看作是一个翻译器,它将你的格式化字符串与数据翻译成需要的结果。当你创建一个Formatter对象的时候,需要向构造器传递一些信息,告诉它最终的结果将向哪里输出:
import java.util.*;
//ellipsis
Formatter f = new Formatter(System.out);
f.format() //用法同上
类型转换字符: | |
---|---|
d 整数型(十进制) | e 浮点数(科学计数) |
c Unicode字符 | x 整数(十六进制) |
b Boolean值 | h 散列码(十六进制) |
s String | % 字符”%” |
f 浮点数(十进制) |