您的位置:首页 > 编程语言 > Java开发

Java编程思想之字符串

2017-08-15 16:49 429 查看

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                 // Metho
b9f5
d 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 浮点数(十进制)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: