掌握前述的知識後,接下來就可以開始創建自己的工具庫,以便減少或者完全消除重復的代碼。例如,可為System.out.println()創建一個別名,減少重復鍵入的代碼量。它可以是名為tools的一個包(package)的一部分:
//: P.java // The P.rint & P.rintln shorthand package com.bruceeckel.tools; public class P { public static void rint(Object obj) { System.out.print(obj); } public static void rint(String s) { System.out.print(s); } public static void rint(char[] s) { System.out.print(s); } public static void rint(char c) { System.out.print(c); } public static void rint(int i) { System.out.print(i); } public static void rint(long l) { System.out.print(l); } public static void rint(float f) { System.out.print(f); } public static void rint(double d) { System.out.print(d); } public static void rint(boolean b) { System.out.print(b); } public static void rintln() { System.out.println(); } public static void rintln(Object obj) { System.out.println(obj); } public static void rintln(String s) { System.out.println(s); } public static void rintln(char[] s) { System.out.println(s); } public static void rintln(char c) { System.out.println(c); } public static void rintln(int i) { System.out.println(i); } public static void rintln(long l) { System.out.println(l); } public static void rintln(float f) { System.out.println(f); } public static void rintln(double d) { System.out.println(d); } public static void rintln(boolean b) { System.out.println(b); } } ///:~
所有不同的數據類型現在都可以在一個新行輸出(P.rintln()),或者不在一個新行輸出(P.rint())。
大家可能會猜想這個文件所在的目錄必須從某個CLASSPATH位置開始,然後繼續com/bruceeckel/tools。編譯完畢後,利用一個import語句,即可在自己系統的任何地方使用P.class文件。如下所示:
ToolTest.java
所以從現在開始,無論什麼時候只要做出了一個有用的新工具,就可將其加入tools目錄(或者自己的個人util或tools目錄)。
1. CLASSPATH的陷阱
P.java文件存在一個非常有趣的陷阱。特別是對於早期的Java實現方案來說,類路徑的正確設定通常都是很困難的一項工作。編寫這本書的時候,我引入了P.java文件,它最初看起來似乎工作很正常。但在某些情況下,卻開始出現中斷。在很長的時間裡,我都確信這是Java或其他什麼在實現時一個錯誤。但最後,我終於發現在一個地方引入了一個程序(即第17章要說明的CodePackager.java),它使用了一個不同的類P。由於它作為一個工具使用,所以有時候會進入類路徑裡;另一些時候則不會這樣。但只要它進入類路徑,那麼假若執行的程序需要尋找com.bruceeckel.tools中的類,Java首先發現的就是CodePackager.java中的P。此時,編譯器會報告一個特定的方法沒有找到。這當然是非常令人頭疼的,因為我們在前面的類P裡明明看到了這個方法,而且根本沒有更多的診斷報告可為我們提供一條線索,讓我們知道找到的是一個完全不同的類(那甚至不是public的)。
乍一看來,這似乎是編譯器的一個錯誤,但假若考察import語句,就會發現它只是說:“在這裡可能發現了P”。然而,我們假定的是編譯器搜索自己類路徑的任何地方,所以一旦它發現一個P,就會使用它;若在搜索過程中發現了“錯誤的”一個,它就會停止搜索。這與我們在前面表述的稍微有些區別,因為存在一些討厭的類,它們都位於包內。而這裡有一個不在包內的P,但仍可在常規的類路徑搜索過程中找到。
如果您遇到象這樣的情況,請務必保證對於類路徑的每個地方,每個名字都僅存在一個類。