String 对象是不可变的,JDK中String类的方法都是创建一个全新的String对象,即使是修改串的方法。可以用 == 运算观察一下。 String参数传递也是传递的引用的复制。
String不可变是源于这么一种思想:参数传递给方法是提供方法的信息的,而不是让方法改变参数的。
任何指向String对象的引用都不可能改变他的值,因此引用之间就互不影响。但是不可变得特性会有效率问题。例如String仅有的两个重载操作符 + 和 += 。他们可以让String和各种类型的连接(基本类型会装箱,然后和引用型一样调用toString())。使用JDK自带的反编译工具javap -c 反编译后会发现String的+运算符实际上 使用了StringBuilder类完成可能的多个参数append()方法(一个参数调用一次),然后使用toString() 生成String对象。
Java不允许重载操作符。
切记不要在循环中使用String的+或+= 方法,因为在每次循环中都会新建StringBuilder对象,append后toString 。而应该在循环外new一个StringBuilder对象。 。 sb.append(a + ":" + b); 也会让编译器掉入陷阱。
因此,对字符串的任何拼接,都应该拆成对StringBuilder对象的单独参数的append操作。
对编译器的的源码优化最好使用javap -c查看 。就能知道怎么写性能好了。
StringBuilder对字符串修改有丰富的方法,如insert, replace, substring,reverse,append,toString,delete。
与StringBuffer相比,StringBuilder是线程不安全的,但是是可变字符串操作的首选工具类。
Java中的所有类根本上都是继承Object类,所以都有toString方法。容器类也是,而且容器类也复写了toString方法。例如ArrayList.toString方法会遍历成员逐个调用toString()方法。
若希望toString打印出对象的内存地址,可以使用this关键字。例如:
public class c{
public String toString(){
// SHOULD BE super.toString()
return "Class c address:" + this + "\n";
}
public static void main(String args[]){
List v = new ArrayList();
for(int i = 0 ; i < 10; i ++){ v.add(new c()); }
System.out.println(v);
}
}
但是上面的 "Class c address:" + this + "\n" 会出现异常,因为编译器会先生成一个StringBuilder,然后append进每一个参数,当遇到 this 时,调用他的toString方法,于是发生了递归调用。
所以,这就是因为多态造成的结果。所以要调用Object.toString()方法即可,即将 this 改成 super.toString()。
C语言中使用printf可以打印栈上的内容。
熟记String的常用方法。
System.out.format() 和 System.out.printf() 方法是一样的。
Formatter类的使用:
构造他的对象需要一个OutputStream、File或者PrintStream对象。然后就可以用format方法输出了。
Formatter f = new Formatter(System.out);
f.format("%s %d", "asd",2);
再复习一下printf的格式化规则。
%[参数索引$][标志][宽度][.精确度]格式字母
标志是例如 - ,表示左对齐方向。
精确度用在String类型上表示打印的长度。不能用在整形上。
String.format() 方法类似C中的sprintf, 其内部使用了Formatter类。
Java中的正则比别的语言要多加一个'',例如 r‘\d’ 表示数字。 换行和制表符之类的还是原样。
相关方法:
String对象.matches(正则式) //进行正则测试
String对象.split(正则式) //按照正则式将字符串切分返回字符串数组
String对象.replaceFirst(正则式) //
String对象.replaceAll(正则式) //
java.util.regex 包中的Pattern类是正则类,(别的编程语言都是叫Regex)。
其中,Pattern对象主要是用来对正则字符串进行编译或其他操作的类,还可以对字符串进行使用正则的切分。
Matcher类包含有大量的匹配查询或者匹配替换等操作。
String regstr = "(.+?)\\w\\s";
Pattern p = Pattern.compile(regstr, Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE); // 忽略大小写。元字符'.'匹配行终结符。开启多行查找,即元字符'^'和'$'匹配行头和行尾,平时这两个元字符匹配完整串的开始和结束。
Matcher m = p.matcher("asddcdedd");
while(m.find()){
System.out.println("find " + m.group(0) + m.start() );
}
其中,Matcher对象的group(int gronum)和其他语言的正则类似,0表示全部匹配式,其他正数是分组号。start(int gronum)和end(int gronum)也类似。
将JDK文档中正则类加入搜藏随时查询。
正则复习: ?放在量词后表示非贪婪模式。放在元素后表示{1,}。
\W \D \S 这种一般大写的表示非...。比如\w表示单词, \W表示非单词,即空白符。
Scanner的构造器可以接受任何类型的输入对象,包括File对象,InputStream,String字符串或者实现了Readable接口的类对象!!!。然后,就可以使用Scanner对象的nextXX()系列的方法将来自于各种输入源的流进行方便的读取。下面是各种读取的效果代码:
Scanner s = new Scanner("TRUE asd 213");
s.useDelimiter(" ");
System.out.println(s.nextBoolean());
System.out.println(s.next());
System.out.println(s.nextInt());
File path = new File("test1.txt");
//BufferedWriter fw = new BufferedWriter(new FileWriter(path));
//fw.write("this.is.a.test.line");
//fw.flush();
//fw.close();
//s = new Scanner(path);
//s.useDelimiter("\\.");
//while(s.hasNext()){
//System.out.println(s.next());
//}
FileOutputStream fos = new FileOutputStream(path);
FileChannel fw = fos.getChannel();
ByteBuffer bb = ByteBuffer.allocate(256);
//bb.put(ByteBuffer.wrap("this.is.a.test.line".getBytes()));
CharBuffer cb_view = bb.asCharBuffer();
cb_view.put("this.is.a.test.line");
fw.write(bb);
fw.close();
fos.close();
s = new Scanner(path);
while(s.hasNext()){
System.out.println(s.next());
}
//Output:
//true
//asd
//213