Thinking in Java 整理笔记:字符串
Posted Chouney
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Thinking in Java 整理笔记:字符串相关的知识,希望对你有一定的参考价值。
不可变String: 1.String对象时不可变的:指的是每一个看起来会修改String值的 方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容。(用=号赋值时实际上是创建了另一个对象)重载“+”与StringBuilder : 2.不可变性会带来一定的效率问题。为String对象重载的“+”操作符就是例子。 当对String对象使用重载的+操作符时,编译器会先创建了一个StringBuilder对象,用以构造最终的String,并为每个字符串调用一次StringBuilder的append()方法,最后调用其toString方法生成最后的String对象。 如: String s= "123456 12355"; s+="222"; JVM字节码如下: 0: ldc #32 // String 123456 12355
2: astore_1
3: new #16 // class java/lang/StringBuilder
6: dup
7: aload_1
8: invokestatic #34 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
11: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
14: ldc #40 // String 222
16: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #29 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_1
23: return 3.操作符在以下情况需要进行优化( 在循环内部需要对String对象用到操作符+时): String s= "123456 12355"; for(int i = 1;i<5;i++) s+=i; 其JVM字节码如下: 0: ldc #32 // String 123456 12355
2: astore_1
3: iconst_1
4: istore_2
5: goto 30
8: new #16 // class java/lang/StringBuilder
11: dup
12: aload_1
13: invokestatic #34 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
16: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
19: iload_2
20: invokevirtual #40 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
23: invokevirtual #29 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
26: astore_1
27: iinc 2, 1
30: iload_2
31: iconst_5
32: if_icmplt 8
35: return
其中8行,32行表示条件循环, 可见每循环一次都要创建一个StringBuilder对象 解决此方法如下: StringBuilder s= new StringBuilder("123456 12355"); for(int i = 1;i<5;i++) s.append(i); System.out.println(s.toString()); 其JVM字节码如下: 0: new #16 // class java/lang/StringBuilder
3: dup
4: ldc #32 // String 123456 12355
6: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
9: astore_1
10: iconst_1
11: istore_2
12: goto 24
15: aload_1
16: iload_2
17: invokevirtual #34 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
20: pop
21: iinc 2, 1
24: iload_2
25: iconst_5
26: if_icmplt 15
29: getstatic #37 // Field java/lang/System.out:Ljava/io/PrintStream;
32: aload_1
33: invokevirtual #29 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
36: invokevirtual #43 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
39: return
可以看出在循环内部使用StringBuilder对象的append方法添加并在最后使用toString方法生成成String对象 (在这种情况下就需要在循环内部避免使用+操作符,用append取代)
4.StringBuilder提供了丰富而全面的方法,包括insert()、repleace()、substring()甚至reverse(),但是最常用的还是append()和toString()。还有delete方法,参数是字符索引。 PS:这里注意StringBuilder是Java SE5引入的,在这之前Java用的是StringBuffer。候着是线程安全的,因此开销会大些。
5.如果想在toString()方法中返回this(想要打印出对象的内存地址时),如果代码如下: public String toString() return "ssss"+this; 则会产生编译器报错, 此时因为+操作符,编译器会将this转换为String类型,如此又调用了toString()方法,产生死循环。若想要输出对象内存地址,应该调用Object.toString()方法,也就是不 该使用this,而是应该调用super.toString()方法。
6.重复强调1中声明:当需要改变字符串的内容时,String类的方法都会返回一个新的String对象。同时如果内容没有发生改变,String的方法只是返回指向原对象的引用而已。
格式化输出: 7.Java SE5 引入的format方法可用于PrintStream或PrintWriter对象,其中也包括System.out对象。模仿的是C语言的printf()
8.在Java中所有新的格式化功能都由java.util.Formatter类处理。可以讲Formatter看作一个翻译器,构造器经过重载可以接受多种输出目的地,最常用的是PrintStream(),OutputStream和File Formatter f = new Formatter(System.out); f.format("%s hahaha %d","My name is",5); //My name is hahaha 5
9.格式化说明符: %[argument_index$][flags][width][.precision]conversion 其中需要注意的是:最小尺寸由width实现(默认右对齐,不过可以通过使用-width改变方向)
10.String.format()接受与Formatter.format()方法一样的参数,但返回一个String对象
正则表达式: 11.需要注意的是,在其他语言中,\\\\表示“我想要在正则表达式中插入一个普通的(字面上的)反斜线,请不要给它任何特殊的意义。”而在Java中,\\\\的意思是“我要插入一个正则表达式的反斜线”(就会转义,无义变有义,如\\\\d,有义变无义,如\\\\+)。如果想要一个普通的反斜线,则应该\\\\\\\\。但是换行和制表符之类的只需要使用单反斜线:\\n\\t。
12.量词:略
13.接口CharSequencecong CharBuffer、String、StringBuffer、StringBuilder类之中抽象出了字符序列的一般化定义,这些类都实现了该接口: interface CharSequence charAt(int i); length(); subSequence(int start,int end); toString();
14.Java中与正则表达式有关的类有:Scanner、Pattern、Match、String
15.String.matchs()用于正则完整的匹配字符串,返回true或者false;其还自带了split()方法用于分割以及replaceXX系列的方法用以正则替换。
16.Pattern和Matcher:static Pattern.compile(String regex) 编译生成Pattern对象,调用Pattern对象的matcher(内容)方法。
Matcher常用拥有的方法: find()、group()、start()、end(): while (m.find()) System.out.println(m.group()+" at position "+m.start()+" - "+m.end()); matches()判断整个字符串匹配,lookingAt()判断字符串的始部分是否能够匹配 reset(内容)将现有Matcher对象应用于一个新的字符序列(可以被用来做动态匹配,每次reset(新内容))
Pattern常用的方法: static boolean matches(String regex, CharSequence input) 同上 split() compile(String regex,int flag):其中 flag的取值范围如下:
Pattern.CANON_EQ,当且仅当两个字符的"正规分解(canonical decomposition)"都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a\\u030A"会匹配"?"。默认情况下,不考虑"规范相等性(canonical equivalence)"。
Pattern.CASE_INSENSITIVE(?i) 默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。 要想对Unicode字符进行大小不明感的匹 配,只要将UNICODE_CASE与这个标志合起来就行了。
Pattern.COMMENTS(?x) 在这种模式下,匹配时会忽略(正则表达式里的)空格字符(不是指表达式里的"\\\\s",而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。
Pattern.DOTALL (?s) 在这种模式下,表达式'.'可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式'.'不匹配行的结束符。
Pattern.MULTILINE(?m)在这种模式下,'^'和'$'分别匹配一行的开始和结束。此外,'^'仍然匹配字符串的开始,'$'也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
Pattern.UNICODE_CASE(?u) 在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配。默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。
Pattern.UNIX_LINES(?d) 在这个模式下,只有'\\n'才被认作一行的中止,并且与'.','^',以及'$'进行匹配。
17.Scanner的构造器可以接受任何类型的输入对象,包括File、InputStream、String、或者Readable(Java SE5新接口,表示’具有read()方法的某种东西‘,如BufferedReader)。
18.有了Scanner,所有的输入、分词以及翻译的操作都隐藏在不同类型的nextXXX方法中。普通的next方法返回下一个String。所有基本类型(除char外)都有对应的next方法。所有的next方法,只有在找到一个完整的分词后才会返回。 PS:需要注意的是,Scanner的使用并不需要添加Try区,因为Scanner有一个假设,在输入结束时会抛出IOException,所以Scanner会把IOException吞掉。通过ioException()方法可以找到最近发生的异常。
19.默认情况下,Scanner根据空白字符对输入进行分词。也可以Scanner使用useDelimiter()来设置定界符(支持正则),同时还有一个delimiter()方法返回当前正在作为定界符使用的Pattern对象
20.Scanner的next()方法配合正则是,会找到下一个匹配该模式的输入部分。
以上是关于Thinking in Java 整理笔记:字符串的主要内容,如果未能解决你的问题,请参考以下文章