对于很多初学者来说,可能会没有感觉到String不可变这件事,下面给个例子先体会下:
class T{
int a;
T(int a){
this.a = a;
}
}
public class TestString {
public static String fun(String s){
return s = "fun";
}
public static T fun(T s){
s.a = 0;
return s;
}
public static void p(String s){
System.out.println(s);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String ss = "ss";
String s = fun(ss);
p("s:"+s);//不建议这么用
p("ss:"+ss);
T tt = new T(1);
T t = fun(tt);
p("t:"+t.a);
p("tt:"+tt.a);
}
}
这里用了另一个类的对象做比较,会发现,一般的对象都会被改变,但是String的对象却不会。
实际上每一个看似修改String的操作,实际上都是重新创建了个String对象,以包含修改后的字符串内容。而最初的String对象却丝毫未动。
java中仅有的两个重载过的操作符是“+”和”+=“。在我们使用重载符的时候,具体是怎么工作的呢?
在我们使用”+“的时候,编译器会自动的创建一个StringBuilder对象,用以构造最终的String,并为字符串调用StringBuilder的append()方法,最后调用toString()生成结果。
现在,也许你会觉得这样就可以随意的使用String对象了,反正编译器会自动优化,可是实际上,编译器优化的能力也是有限的,不如自己使用StringBuilder。
当我们想要输出一个类的地址时怎么办呢?
你可能会觉得很简单,用this关键字就可以。但是你会发现,这样会产生很长的异常。
究其原因,因为编译器看到一个String对象后面跟着一个“+”,而再后面的对象不是String,于是编译器试着将this转换成一个String类型,怎么转换呢,正是通过调用this的toString方法,于是就发生了递归调用。
format()方法模仿自c语音的printf,举个简单的例子:
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.format("%d,%f", 1,0.01);
}
在java中所有格式化功能都由Formatter类处理,可以将Formatter看做一个翻译器,当你创建Formatter对象的时候,需要指出向哪里输出,下面有个例子可以很清晰的看出来:
public static void main(String[] args) {
// TODO Auto-generated method stub
PrintStream out = System.out;
Formatter f =new Formatter(out);
f.format("%d,%f", 1,0.01);
}
String.format()是一个static方法,返回String对象,用法和上文类似,下面是个例子:
public class TestStringFormat {
public static void main(String[] args) {
// TODO Auto-generated method stub
String a="a";
String b="b";
int c = 1;
String test = String.format("%s+%s=%d", a,b,c);
System.out.println(test);
}
}
一般来说,比起功能有限的String类,我们更愿意使用正则表达式,我们只需要导入java.util.regex包,然后使用Pattern.compile方法来编译你的正则表达式即可,它会根据你的String类型的正则表达式生成一个Pattern对象,接下来,把你想要检索的字符串传入Pattern对象的matcher方法,该方法会生成一个Matcher对象,它有很多功能可用。
public class TestPattern {
public static void main(String[] args) {
// TODO Auto-generated method stub
String[] test = {"a","abc","bcd","bc","a","b"};
for(String t:test){
Pattern p = Pattern.compile("a+");
Matcher m = p.matcher(t);
while(m.find()){
System.out.println(t+":"+m.group());
}
}
}
}
输出:
a:a
a:a
b:b
split方法将输入字符串断开成字符对象数组,断开边界由正则表达式确定。
有一个快速而方便的方法,可以按照通用边界断开输入文本:
public class TestPattern {
public static void main(String[] args) {
// TODO Auto-generated method stub
String test = "ab!cabccc!aabca";
String[] tests = Pattern.compile("!").split(test);
for(String t:tests){
System.out.print(t+",");
}
}
}
输出:
ab,cabccc,aabca,
替换操作比较简单,String有replaceAll方法,可以将所有字符进行替换,下面有个简单的例子:
public class TestPattern {
public static void main(String[] args) {
// TODO Auto-generated method stub
String content = "a sd df !He is Tom,Tom fall in love with Jery! fg jjk kl";
Pattern p = Pattern.compile("!(.*)!");
Matcher m = p.matcher(content);
if(m.find()){
content = m.group(1);
content = content.replaceAll("Tom", "Marry");
}
System.out.println(content);
}
}
输出:
He is Marry,Marry fall in love with Jery
可以将现有的Matcher对象应用于一个新的字符序列:
public class TestPattern {
public static void main(String[] args) {
// TODO Auto-generated method stub
String content = "a sd df !He is Tom,Tom fall in love with Jery! fg jjk kl";
String content2 = "a sd df !She is Tom,Tom fall in love with Jery! fg jjk kl";
Pattern p = Pattern.compile("!(.*)!");
Matcher m = p.matcher(content);
if(m.find()){
content = m.group(1);
content = content.replaceAll("Tom", "Marry");
}
m.reset(content2);
if(m.find()){
content = m.group(1);
}
System.out.println(content);
}
}
输出:
She is Tom,Tom fall in love with Jery