String对象是不可变的,每一次修改实际上都是创建了一个新的String对象。
String的“+”与“+=”用于拼接字符串,但由于String是可变的,拼接多个字符串时会造成大量的垃圾。Java对此进行了优化,当拼接多个字符串时,编译器自动引用了StringBuilder变量。(新版本与书上例子不同)
使用StringBuilder可以很高效的进行字符串拼接。并且包含了丰富的方法:insert()、replace()、subString()、reverse()。其中append()与toString()比较常用。
public class Concatenation {
public static void main(String[] args) {
String mango = "mango";
String s = "abs" + mango + "def" + 47;
System.out.println(s);
}
}
public class chapter13.Concatenation {
public chapter13.Concatenation();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #7 // String mango
2: astore_1
3: aload_1
4: invokedynamic #9, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
9: astore_2
10: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
13: aload_2
14: invokevirtual #19 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: return
}
对当前class字节码进行反编译生成汇编代码
javac chapter13\Concatenation.java
javap -c chapter13\Concatenation
下面的程序,在覆盖的方法toString中,字符换拼接碰到了对象引用,会自动调用this对象的toString()方法,于是发生了递归调用。
为了消除递归,应该调用super.toString。
import java.util.*;
public class InfiniteRecursion {
public String toString() {
return " InfiniteRecursion address: " + this + "\n";
}
public static void main(String[] args) {
List<InfiniteRecursion> v =
new ArrayList<InfiniteRecursion>();
for(int i = 0; i < 10; i++)
v.add(new InfiniteRecursion());
System.out.println(v);
}
} ///:~
方法 | 参数返回值 | 描述 |
---|---|---|
length() | - | 返回字符串长度 |
charAt() | int索引 | 返回该索引上的char |
toCharArray() | - | 生成char[], 里面包含String所有字符 |
equals(), equalsIgnoreCase() | 与之相比的String | 比较两个字符串内容是否相同 (忽略大小写) |
compareTo, compareToIgnoreCase() | 与之相比的String | 按字典序比较两个字符串的内容 |
contains() | 要搜索的CharSequence() | 如果包含参数的内容,则返回True |
contentEquals() | 与之进行比较的CharSequence或者StringBuffer | 如果包含参数的内容,则返回True |
regionMatcher() | 当前String索引的偏移量与另一个String索引的偏移量,要求比较的长度 | boolean |
startsWith | 可能起始的String,重载增添了offset | boolean |
endsWith | boolean endssWith(String prefix) | boolean |
indexOf(), lastIndexOf | char或char的索引 | 返回目标索引,如果不存在则返回-1 |
subString() | 起始索引,起始+终止索引 | 返回新的String子串 |
concat() | 要连接的String | 返回已给您的String对象,包含两个字符串的拼接 |
replace() | 要替换的字符串,用来替换的字符串 | 返回替换后的String对象,如果没有发生替换,则返回原始对象 |
toLowerCase(), toUpperCase() | - | 改变字符串大小写。若无需改变则返回原始String对象 |
trim() | - | 去掉两端空白字符,若无需改变则返回原始String对象 |
valueOf() | 静态方法,重载版本为Object、boolean、char、int、long、short、float、double | 返回 |
intern() | - | 详细解答 |
Formatter的构造器经过重载可以接受多种输出目的地。
格式:%[argument_inde$][flags][width][.presion]conversion
“-”可以调整对齐方式,默认是右对齐。
import java.util.*;
public class Receipt {
private double total = 0;
private Formatter f = new Formatter(System.out);
public void printTitle(inr) {
f.format("%-15s %5s %10s\n", "Item", "Qty", "Price");
f.format("%-15s %5s %10s\n", "----", "---", "-----");
}
public void print(String name, int qty, double price) {
f.format("%-15.15s %5d %10.2f\n", name, qty, price);
total += price;
}
public void printTotal() {
f.format("%-15s %5s %10.2f\n", "Tax", "", total*0.06);
f.format("%-15s %5s %10s\n", "", "", "-----");
f.format("%-15s %5s %10.2f\n", "Total", "",
total * 1.06);
}
public static void main(String[] args) {
Receipt receipt = new Receipt();
receipt.printTitle();
receipt.print("Jack's Magic Beans", 4, 4.25);
receipt.print("Princess Peas", 3, 5.1);
receipt.print("Three Bears Porridge", 1, 14.29);
receipt.printTotal();
}
} /* Output:
Item Qty Price
---- --- -----
Jack's Magic Be 4 4.25
Princess Peas 3 5.10
Three Bears Por 1 14.29
Tax 1.42
-----
Total 25.06
*///:~
类型转换符 | |
---|---|
d | 整数型(十进制) |
c | Unicode字符 |
b | Boolean值 |
s | String |
f | 浮点数(十进制) |
e | 浮点数(科学计数) |
x | 整数(十六进制) |
h | 散列码(十六进制) |
% | 字符串% |
String.format()接受与Formatter.format()一样的参数,但是返回的是一个String对象。
\表示要插入一个正则表达式的反斜线其后面的字符有特殊的意义,例如,表示一位数字\d,表示\,应该使用\\。
字符 | 含义 |
---|---|
B | 指定字符B |
\xhh | 十六进制为xhh的字符 |
\uhhhh | 十六进制为oxhhhh的Unicode字符 |
\t | 制表符Tab |
\n | 换行符 |
\r | 回车 |
\f | 换页 |
\e | 转义Escape |
字符类 | 含义 |
---|---|
. | 任意字符 |
[abc] | 包含a,b,c的任何字符 |
[^abc] | 除了a,b,c外的任何字符 |
[a-zA-Z] | 从a到z或从A到Z的任何字符 |
abc[hij] | 任意a,b,c,h,i,j字符(合并) |
a-z&[hij] | 任意h,i或j |
\s | 空白符(空格、tab、换行、换页、回车) |
\S | 非空白符[^s] |
\d | 数字[0-9] |
\D | 非数字[^0-9] |
\w | 词字符[a-zA-Z0-9] |
\W | 非词字符[^\w] |
逻辑操作符 | 含义 |
---|---|
XY | Y在X后面 |
X|Y | X或Y |
(X) | 捕获组。可以在表达式中用\i引用第i个捕获组 |
边界匹配符 | 含义 |
---|---|
^ | 一行的起始 |
$ | 一行的结束 |
\b | 词的边界 |
\B | 非词的边界 |
\G | 前一个匹配的结束 |
贪婪型 | 勉强型 | 占有型 | 含义 |
---|---|---|---|
X? | X?? | X?+ | 至多一个X |
X* | X*? | X*+ | 任意个X |
X+ | X+? | X++ | 至少一个X |
X{n} | X{n}? | X{n}+ | 恰好n次X |
X{n,} | X{n,}? | X{n}+ | 至少n次X |
X{n,m} | X{n,m}? | X{n, m}+ | X至少n次且不超过m次 |
表达式通常用圆括号包围起来,以便按照我们期望的效果去执行。
Pattern与Matcher组合是比String强大的正则表达式工具。
用法:
import java.util.regex.*;
// import static net.mindview.util.Print.*;
public class Finding {
public static void main(String[] args) {
Matcher m = Pattern.compile("\\w+")
.matcher("Evening is full of the linnet's wings");
while(m.find())
System.out.print(m.group() + " ");
System.out.println();
int i = 0;
while(m.find(i)) {
System.out.print(m.group() + " ");
i++;
}
}
} /* Output:
Evening is full of the linnet s wings
Evening vening ening ning ing ng g is is s full full ull ll l of of f the the he e linnet linnet innet nnet net et t s s wings wings ings ngs gs s
*///:~
split()方法可以很便捷的将输入字符串断开形成对象数组。
通过reset()方法,可以将现有的Matcher对象应用到新的字符序列。如果使用不带参的reset(),可以将Matcher对象重新设置到当前字符序列的起始位置。
可以用更加强大的split和正则表达式代替。