首页 > 代码库 > java解惑之字符之谜(谜题21)
java解惑之字符之谜(谜题21)
谜题21:我的类是什么?镜头2
下面的程序所要做的事情正是前一个谜题所做的事情,但是它没有假设斜杠符号就是分隔文件名组成部分的符号。相反,该程序使用的是java.io.File.separetor,它被指定为一个公共的String域,包含了平台相关的文件名分隔符。这个程序会打印正确的、平台相关的类文件名吗?该程序是从这个类文件中被加载的。
package com.javapuzzlers; import java.io.File; public class MeToo{ public static void main(String[] args){ System.out.println(MeToo.class.getName().replaceAll("\\.",File.separator) + ".class"); } }
之前就说了这个程序是没有假设斜杠符号是分隔文件名组成部分的符号,所以这个程序根据底层平台的不同会显示两种行为中的一种。如果斜杠是文件分隔符的话(例如在Unix中),那就该程序就会打印com/javapuzzlers.MeToo.class,这是正确的。如果反斜杠才是文件分隔符的话(例如在Windows中),那么该程序就将出现异常,会打印像下面这样的内容:
Exception in thread "main" StringIndexOutOfBoundsException:String index out of range:1 at java.lang.String.charAt(String.java:558) at java.util.regex.Matcher.appendReplacement(Mather.java:696) at java.util.regex.Matcher.replaceAll(Mather.java:806) at java.lang.String.replaceAll(String.java:2000) at com.javapuzzlers.MeToo.main(MeToo.java:6)
尽管这种行为是平台相关的,但也不是我们所期待的。为什么在Windows上会出错呢,到底是出了什么错呢?从上面打印的异常中,我们可以得知在程序的第5行出了异常。事实证明,String.replaceAll的第二个参数不是一个普通的字符串,而是一个替代字符串,就像在java.util.regex规范中所定义的那样。在替代字符串中出现的反斜杠会把紧随其后的字符进行转义,从而导致其被按字面含义而处理了。当你在Windows上运行该程序时,替代字符串是单独的一个反斜杠,它是无效的。那么,应该怎么样来解决此问题呢?5.0版本提供了不是一个而是两个新的方法来解决它。第一个方法是java.util.regex.Matcher.quoteReplacement,它将字符串转换成相应的替代字符串。如下:
System.out.println(MeToo.class.getName().replaceAll("\\.",Matcher.quoteReplacement(File.separator)) + ".class");
那么第二种方法提供了更好的解决方案,该方法就是String.replace(CharSequence,CharSequence),它所做的事情和String.replaceAll相同,但是它将模式和替代物都当作字符串字面常量处理。如下:
System.out.println(MeToo.class.getName().replace(".",File.separator) + ".class");
但是如果你使用的是较早版本的java又该怎么办呢?那只能完全不使用正则表达式,而使用String.replace(char,char)也许更容易:
System.out.println(MeToo.class.getName().replace('.',File.separatorChar) + ".class");
那么从这本谜题和前一个谜题中,我们知道了在使用不熟悉的类库方法时一定要格外小心。当你心存疑虑时,就要求助于javadoc。另外,正则表达式是很棘手的,它所引发的问题倾向于在运行时刻而不是在编译时刻暴露出来。
java解惑之字符之谜(谜题21)