友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第148部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


    identMap = new MultiStringMap();  

  private StreamTokenizer in;  

  public ClassScanner() {  

    path = new File(〃。〃);  

    fileList = path。list(new JavaFilter());  

    for(int i = 0; i 《 fileList。length; i++) {  

      System。out。println(fileList'i');  

      scanListing(fileList'i');  

    }  

  }  

  void scanListing(String fname) {  

    try {  

      in = new StreamTokenizer(  

          new BufferedReader(  

            new FileReader(fname)));  

      // Doesn't seem to work:  

      // in。slashStarments(true);  

      // in。slashSlashments(true);  

      in。ordinaryChar('/');  

      in。ordinaryChar('。');  

      in。wordChars('_'; '_');  

      in。eolIsSignificant(true);  

      while(in。nextToken() !=   

            StreamTokenizer。TT_EOF) {  

        if(in。ttype == '/')  

          eatments();  



                                                                                             634 


…………………………………………………………Page 636……………………………………………………………

        else if(in。ttype ==   

                StreamTokenizer。TT_WORD) {  

          if(in。sval。equals(〃class〃) ||   

             in。sval。equals(〃interface〃)) {  

            // Get class name:  

               while(in。nextToken() !=   

                     StreamTokenizer。TT_EOF  

                     && in。ttype !=   

                     StreamTokenizer。TT_WORD)  

                 ;  

               classes。put(in。sval; in。sval);  

               classMap。add(fname; in。sval);  

          }  

          if(in。sval。equals(〃import〃) ||  

             in。sval。equals(〃package〃))  

            discardLine();  

          else // It's an identifier or keyword  

            identMap。add(fname; in。sval);  

        }  

      }  

    } catch(IOException e) {  

      e。printStackTrace();  

    }  

  }  

  void discardLine() {  

    try {  

      while(in。nextToken() !=   

            StreamTokenizer。TT_EOF  

            && in。ttype !=   

            StreamTokenizer。TT_EOL)  

        ; // Throw away tokens to end of line  

    } catch(IOException e) {  

      e。printStackTrace();  

    }  

  }  

  // StreamTokenizer's ment removal seemed  

  // to be broken。 This extracts them:  

  void eatments() {  

    try {  

      if(in。nextToken() !=   

         StreamTokenizer。TT_EOF) {  

        if(in。ttype == '/')  

          discardLine();  

        else if(in。ttype != '*')  

          in。pushBack();  

        else   

          while(true) {  

            if(in。nextToken() ==   

              StreamTokenizer。TT_EOF)  

              break;  

            if(in。ttype == '*')  

              if(in。nextToken() !=   



                                                                                        635 


…………………………………………………………Page 637……………………………………………………………

                StreamTokenizer。TT_EOF  

                && in。ttype == '/')  

                break;  

          }  

      }  

    } catch(IOException e) {  

      e。printStackTrace();  

    }  

  }  

  public String'' classNames() {  

    String'' result = new String'classes。size()';  

    Enumeration e = classes。keys();  

    int i = 0;  

    while(e。hasMoreElements())  

      result'i++' = (String)e。nextElement();  

    return result;  

  }  

  public void checkClassNames() {  

    Enumeration files = classMap。keys();  

    while(files。hasMoreElements()) {  

      String file = (String)files。nextElement();  

      Vector cls = classMap。getVector(file);  

      for(int i = 0; i 《 cls。size(); i++) {  

        String className =   

          (String)cls。elementAt(i);  

        if(Character。isLowerCase(  

             className。charAt(0)))  

          System。out。println(  

            〃class capitalization error; file: 〃  

            + file + 〃; class: 〃   

            + className);  

      }  

    }  

  }  

  public void checkIdentNames() {  

    Enumeration files = identMap。keys();  

    Vector reportSet = new Vector();  

    while(files。hasMoreElements()) {  

      String file = (String)files。nextElement();  

      Vector ids = identMap。getVector(file);  

      for(int i = 0; i 《 ids。size(); i++) {  

        String id =   

          (String)ids。elementAt(i);  

        if(!classes。contains(id)) {  

          // Ignore identifiers of length 3 or  

          // longer that are all uppercase  

          // (probably static final values):  

          if(id。length() 》= 3 &&  

             id。equals(  

               id。toUpperCase()))   

            continue;  

          // Check to see if first char is upper:  



                                                                                         636 


…………………………………………………………Page 638……………………………………………………………

          if(Character。isUpperCase(id。charAt(0))){  

            if(reportSet。indexOf(file + id)  

                == …1){ // Not reported yet  

              reportSet。addElement(file + id);  

              System。out。println(  

                〃Ident capitalization error in:〃  

                + file + 〃; ident: 〃 + id);  

            }  

          }  

        }  

      }  

    }  

  }  

  static final String usage =  

    〃Usage: n〃 +   

    〃ClassScanner classnames …an〃 +  

    〃tAdds all the class names in this n〃 +  

    〃tdirectory to the repository file n〃 +  

    〃tcalled 'classnames'n〃 +  

    〃ClassScanner classnamesn〃 +  

    〃tChecks all the java files in this n〃 +  

    〃tdirectory for capitalization errors; n〃 +  

    〃tusing the repository file 'classnames'〃;  

  private static void usage() {  

    System。err。println(usage);  

    System。exit(1);  

  }  

  public static void main(String'' args) {  

    if(args。length 《 1 || args。length 》 2)  

      usage();  

    ClassScanner c = new ClassScanner();  

    File old = new File(args'0');  

    if(old。exists()) {  

      try {  

        // Try to open an existing   

        // properties file:  

        InputStream oldlist =  

          new BufferedInputStream(  

            new FileInputStream(old));  

        c。classes。load(oldlist);  

        oldlist。close();  

      } catch(IOException e) {  

        System。err。println(〃Could not open 〃  

          + old + 〃 for reading〃);  

        System。exit(1);  

      }  

    }  

    if(args。length == 1) {  

      c。checkClassNames();  

      c。checkIdentNames();  

    }  

    // Write the class names to a repository:  



                                                                                        637 


…………………………………………………………Page 639……………………………………………………………

    if(args。length == 2) {  

      if(!args'1'。equals(〃…a〃))  

        usage();  

      try {  

        BufferedOutputStream out =  

          new BufferedOutputStream(  

            new FileOutputStream(args'0'));  

        c。classes。save(out;  

          〃Classes found by ClassScanner。java〃);  

        out。close();  

      } catch(IOException e) {  

        System。err。println(  

          〃Could not write 〃 + args'0');  

        System。exit(1);  

      }  

    }  

  }  

}  

  

class JavaFilter implements FilenameFilter {  

  public boolean accept(File dir; String name) {  

    // Strip path information:  

    String f = new File(name)。getName();  

    return f。trim()。endsWith(〃。java〃);  

  }  

} ///:~  

  

MultiStringMap 类是个特殊的工具,允许我们将一组字串与每个键项对应(映射)起来。和前例一样,这里 

也使用了一个散列表(Hashtable),不过这次设置了继承。该散列表将键作为映射成为Vector 值的单一的 

字串对待。add()方法的作用很简单,负责检查散列表里是否存在一个键。如果不存在,就在其中放置一个。 

getVector()方法为一个特定的键产生一个 Vector;而printValues()将所有值逐个Vector 地打印出来,这 

对程序的调试非常有用。  

为简化程序,来自标准 Java 库的类名全都置入一个 Properties (属性)对象中(来自标准Java 库)。记住 

Properties 对象实际是个散列表,其中只容纳了用于键和值项的 String 对象。然而仅需一次方法调用,我 

们即可把它保存到磁盘,或者从磁盘中恢复。实际上,我们只需要一个名字列表,所以为键和值都使用了相 

同的对象。  

针对特定目录中的文件,为找出相应的类与标识符,我们使用了两个MultiStringMap:classMap 以及 

identMap。此外在程序启动的时候,它会将标准类名仓库装载到名为classes 的Properties 对象中。一旦在 

本地目录发现了一个新类名,也会将其加入classes 以及classMap 。这样一来,classMap 就可用于在本地目 

录的所有类间遍历,而且可用 classes 检查当前标记是不是一个类名(它标记着对象或方法定义的开始,所 

以收集接下去的记号——直到碰到一个分号——并将它们都置入 identMap )。  

ClassScanner 的默认构建器会创建一个由文件名构成的列表(采用FilenameFilter 的JavaFilter 实现形 

式,参见第 10章)。随后会为每个文件名都调用 scanListing()。  

在 scanListing() 内部,会打开源码文件,并将其转换成一个StreamTokenizer。根据Java 帮助文档,将 

true 传递给 slashStartments()和 slashSlashments()的本意应当是剥除那些注释内容,但这样做似 

乎有些问题(在Java 1。0 中几乎无效)。所以相反,那些行被当作注释标记出去,并用另一个方法来提取注 

释。为达到这个目的,'/'必须作为一个原始字符捕获,而不是让StreamTokeinzer 将其当作注释的一部分对 

待。此时要用ordinaryChar()方法指示StreamTokenizer 采取正确的操作。同样的道理也适用于点号 

 ('。'),因为我们希望让方法调用分离出单独的标识符。但对下划线来说,它最初是被StreamTokenizer 当 

作一个单独的字符对待的,但此时应把它留作标识符的一部分,因为它在 static final值中以 TT_EOF 等等 

形式使用。当然,这一点只对目前这个特殊的程序成立。wordChars()方法需要取得我们想添加的一系列字 

符,把它们留在作为一个单词看待的记号中。最后,在解析单行注释或者放弃一行的时候,我们需要知道一 



                                                                                       638 


…………………………………………………………Page 640……………………………………………………………

个换行动作什么时候发生。所以通过调用 eollsSignificant(true) ,换行符(EOL)会被显示出来,而不是 

被StreamTokenizer 吸收。  

scanListing()剩余的部分将读入和检查记号,直至文件尾。一旦 nextToken()返回一个 final static值— 

—StreamTokenizer。TT_EOF ,就标志着已经抵达文件尾部。  

若记号是个'/',意味着它可能是个注释,所以就调用eatments(),对这种情况进行处理。我们在这儿唯 

一感兴趣的其他情况是它是否为一个单词,当然还可能存在另一些特殊情况。  

如果单词是 class (类)或interface (接口),那么接着的记号就应当代表一个类或接口名字,并将其置入 

classes和 classMap。若单词是 import或者package,那么我们对这一行剩下的东西就没什么兴趣了。其他 

所有东西肯定是一个标识符(这是我们感兴趣的),或者是一个关键字(对此不感兴趣,但它们采用的肯定 

是小写形式,所以不必兴师动众地检查它们)。它们将加入到 identMap。  

discardLine()方法是一个简单的工具,用于查找行末位置。注意每次得到一个新记号时,都必须检查行末。  

只要在主解析循环中碰到一个正斜杠,就会调用eatments()方法。然而,这并不表示肯定遇到了一条注 

释,所以必须将接着的记号提取出来,检查它是一个正斜杠(那么这一行会被丢弃),还
返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!