Java编程思想之字符串

来源:互联网 发布:淘宝好的男装店 编辑:程序博客网 时间:2024/05/23 23:32

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);    }}/*运行结果:helloHELLOhello*/

当把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  //自动填充aregionMatches: true  //部分匹配(应注意空白字符不能被忽略)replace:   hh hhvalueOf: 3  //返回一个表示参数内容的Stringintern:   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 浮点数(十进制)
原创粉丝点击