8.1 包的概念
包是由.class文件組成的一個集合,.class文件時可以用Java解釋其解釋執行的文件,它也是由Java源的文件,即.Java文件經編譯而生成的。Java是一種面向對象的語言,它的特點就是重用,包就是組織和管理.class文件的一種工具,因此,它存在的目的就是幫助我們實現代碼的重用。包是一種松散的概念,一般情況下,功能相同或者相關的類組織在一個包中,例如java.io包中的類都與輸入、輸出有關,java.applet包中的類都與applet程序有關。 8.1.1 構建包 一個包事實上就是一個文件夾,這個文件夾中存放着.class文件。包像目錄結構一樣可以由多層結構,而各層之間以“.”來分隔,如java.io,java.awt,java.awt.color等。由於Java的類經常需要在互聯網上運行,所以有可能出現同名的類,程序就不知道使用哪一個類了。但如果把類都放在不同的包中,並且使包的名字獨一無二,就不會出現混亂狀況。 程序中定義包用package這個關鍵詞,它的格式如下: package 包名: 例如: package MyJavaProgram; package cn.com.companyname.myname 這個語句必須放在一個源文件的第一句,並且語句前面無空格。包名一般全部用小寫。我們知道一個源文件可能有多個類,其中只有一個類是公共類,這些類經編譯都會產生.class文件,上面的意思是,這個源文件中的類,經編譯產生的.class文件屬於一個包,名為MyJavaProgram。這就定義了MyJavaProgram包。一般把要打包的源文件放到包中,然后再包中對源文件進行編譯,就把.class文件放入包中了。當然javac編譯器還有幾個參數,可以實現確定源文件來源和.class文件放置等功能,可以實現源文件和.class文件不在同一個目錄。下面是各種參數及其解釋。 -g 生成所有debug信息 -g:none 不生成任何debug信息 -g:{lines,vars,source} 只生成部分debug信息 -O 優化 -nowarn 不生成警告 -verbose 輸出編譯器的工作記錄 -deprecation 輸出所有過期API的位置 -classpath<path> 聲明查找用戶類庫的路徑 -sourcepath<path> 聲明查找源文件的路徑 -bootclasspath<path> 覆蓋引導類文件路徑 -extdirs<dirs> 覆蓋安裝擴展路徑 -d<directory> 聲明將生成的.class文件放在何處 -enconding<encoding> 聲明源文件的編碼方式 -traget<release> 未指定版本的虛擬機生成類文件 8.1.2 包的引用 用import語句就可以引入所需的公共類,如: import java.io.*; 這個語句表示java.io中所有的公共類被引入當前包。系統先根據classpath只是的路徑,然后按照包名找到所需的類,如classpath為c:\package\mypakage,而包名為cn.com.companyname.myname,系統則按照以下路徑去尋找所需的類:c:\package\mypackage\cn\com\companyname\myname,也就是把環境變量和包名相連,形成路徑,然后在這個路徑下尋找類。對於Java類庫,由於安裝時已經自動注冊了路徑,所以不需要添加classpath,而使用自己定義的包中的類就必須更改classpath。 還有一種方法使用某個包中的類,就是在程序中寫全它的包名,但很麻煩,而不使用import語句,如: java.io.FileInputStream in = new java.io.FileInputStream(); 如果我們使用了一個包中的大多數類,可是使用通配符的方式引用包,否則,最好把需要類一一列出來,這樣可以節省大量系統資源。 8.2 Java語言類庫的結構 Java 2平台類庫1.3.1版共為程序員提供了76個包,每個包都分別負責不同的功能,除了java.lang之外,其它包的內容只要經過import語句引用,就可以在程序中使用。所有這些類的介紹和使用方法,Java都提供了極其完善的技術文檔,這種機制在極大程度上釋放了程序員,讓他們何以把更多的時間放在對象的設計上,而不是語法和一些局部算法上。 為了方便讀者自己使用Java文檔,我們先把Java提供的這些包介紹一下,讀者可以根據自己的需要來查閱。其中,包名后面帶”.*”的表示其中包括一系列相關的包。 表8.1 Java提供的包 包名 內容介紹 java.applet 提供了創建applet需要的類,包括幫助applet訪問其內容的通訊類 java.awt.* 提供了創建用戶界面以及繪制、管理圖形、圖像的類 java.beans.* 提供開發Java Beans需要的類 java.io 提供了通過數據流、對象序列以及文件系統實現的系統輸入、輸出 java.lang.* Java編程語言的基本類庫 java.math 提供了簡明的整數算術以及十進制算數的基本函數 java.net 提供了用於實現網絡通訊應用的所有類 java.rmi.* 提供了與遠程方法調用相關的所有類 java.security.* 提供了設計網絡安全方案需要的類 java.sql 提供了訪問和處理來自於Java標准數據源數據的類 java.text 提供了一些類和接口用於處理文本、日期、數字以及語法獨立於自然語言之外格式的消息 java.util.* 包括集合類、事件處理模式、日期時間工具等各類常用工具包 javax.accessibility 定義了用戶界面組件之間相互訪問的一種機制 javax.naming.* 未命名服務提供了一系列類和接口 javax.rmi.* 為用戶提供了遠程方法調用的應用程序接口 javax.sound.* 提供了MIDI輸入、輸出以及合成需要的類和接口 javax.swing.* 提供了一系列輕量級的用戶界面組件,是目前Java用戶界面常用的包 8.3 java.lang包中的常用類介紹 這個包是Java語言最基本的包,沒有這個包中的類,我們的編程很難,它們是編程最基本內容。這個包中的所有類都有系統自動引入,所以程序不用import語句就可以使用其中的任何一個類。這個包有4個部分:接口、類、例外和錯誤。 8.3.1 Object類 Object類是Java程序中所有類的直接或間接父類,也是類庫中所有類的父類,任何一個類都是由Object類派生出來的,它是繼承樹上的根節點。所以它含有的屬性和方法將被所有的類繼承,下面就是Object類的方法,也是所有類都含有的方法: ● protected Object clone()throws CloneNotSupportedException 生成當前對象的一個復制,並返回這個復制的對象,該對象類型為Object,但所有需要使用該方法的類都必須實現接口cloneable,否則,運行時將拋出CloneNotSupportedException類的例外。 ● public final Class getClass() 返回一個當前對象在運行期的Class類對象。 ● public int hashCode() 返回一個hash code value,不同的對象有不同的hash code value. ● public Boolean equals(Object obj) 如果當前對象與形參對象相同則返回true,否則返回false。 ● public String toString() 返回一個反映這個對象信息的字符串,通常使對象所屬類。 ● public final void notify() 這是關於多線程的方法,這個方法用來喚醒等待對向監視器的多個線程中的一個 ● public final void notifyAll() 這個方法是喚醒所有等待監視器的線程 ● public final void wait(long timeout)throws InterrupedException 這個方法是讓當前線程放棄對這個對象的同步的聲明,即放棄對這個對象的鎖定,進入等待行列,直到由notify()或notifyAll()方法喚醒,或形參中規定的時間到期,timeout的單位是毫秒。 ● public final void wait(long timeout,int nanos)throws InterrupedException 這個方法比上一個多了一個形參,第二個形參的意思是nanoseconds(十億分之一秒),這個方法的等待時間變為兩個形參所指示的時間的和,時間控制更精確。 ● public final void wait()throws InterrupException 這個方法的含義同wait(0) ● protected void finalize()throws Throwable 這個方法用來把對象從內存中清除,由圾收集器自動調用,編程者可以重載這個方法,在對象被清除時,顯示某些信息。 8.3.2 Class類 Class類是非常特殊的,它的對象將伴隨每個類。當一個類X被編譯后,就有一個特殊的對象(Class對象)產生,它隱藏在X.class文件中,Class對象是由編譯系統自動生成的。 為了讀者進一步理解類是在何時載入內存的,先來看一個例子: 例8.1 類的載入時機 SweetShop.java的源文件如下: class Candy{ static{ System.out.println("Loading Candy"); } } classGum{ static{ System.out.println("Loading Gum"); } } class Cookie{ static{ System.out.println("Loading Cookie"); } } public class SweetShop{ public static void main(String[] args){ System.out.println("inside main"); new Candy(); System.out.println("After creating Candy"); try{ Class.forName("Gum"); }catch(ClassNotFoundException e){ e.printStackTrace(); } System.out.println("After Class.forName(\"Gum\")"); new Cookie(); System.out.println("After creating Cookie"); } } 這個程序首先定義了3個類,每個類只有一個靜態初始化器,由於靜態初始化器是在類載入內存時就被執行,所以可用它來指示類何時被載入內存的。然后在每個對象創建之前輸入一定的提示語,,這樣我們就很清楚的看到每個類何時加載內存的了。程序中Class.forName(“Gum”);依據的進一步解釋看下面的部分。程序輸出如下: inside main Loading Candy After creating Candy Loading Gum After Class.forName(“Gum”) Loading Cookie After creating Cookie 從以上的結果可以看出,類的加載是在對象創建的時候。 這個特殊的Class對象含有所屬類的所有信息,可以通過Class類的方法提取這些信息,下面我們就介紹Class類的一些方法。 ● public static Class forName(String className)throws ClassNotFoundException 這個方法是靜態方法,所以用Class直接調用,格式可以參考上面的例題。這個方法的形參是一個類名,方法的返回值是形參指示的類的Class對象。這個方法的結果是產生一個形參所表示的類的Class對象。如: class t=Class.forName(“java.lang.Thread”) ● public String getName() 該方法返回Class對象代表的實體(類、接口、數組、基本數據類型等)的名字。例如,(new Object()).getClass().getName()的值是java.lang.Object,當然可以放到println()語句中輸出。其中的getClass()用來得到當前對象的Class對象,同一個類的對象有相同的Class對象。 GetName()返回的字符串中以不同的字母及符號表示該實體的信息,“[”表示數組,有幾個“[”表示幾維數組,以下的字母代表不同的數據類型,“L”表示類或接口。 再看幾個例子: (new Object[3]).getClass.getName()的值為“[Ljava.lang.Object”,它表示當前Class對象對應着一個一維數組,數組元素是java.lang.Object類的對象。 (new int[3][4][5][6][7][8][9]).getClass().getName()的值為“[[[[[[[I”,它表示當前Class對象對應着一個七維數組,數組元素是int類簡單變量。 ● public Class getSuperclass() 這個方法不同於Object類的方法getClass(),它返回的是一個數組,這些數組成員是Class對象,這些對象是當前類中的成員為公共或接口所對應的Class類的實例。 ● public ClassLoader getClassLoader() ClassLoader是一個抽象類,在java.lang包中。任何一個類加載內存,都是通過一個對象來實現的,這個對象就是它衍生類的實例,因為類的定義都是一字節碼文件形式存在,加載一個類就是讀取這些字節碼。 ● public Class getComponentType() 返回數組成員的類型,如果當前對象不是數組,返回null。 ● public int getModifiers() 返回類或接口的修飾語,例如public,protected,private,final,static和abstract等,但它們用一個int數表示,例如:public為0x0001,final為0x0010,abstract為0x0400,這些數字以十六進制表示,是Java虛擬機用來鑒別修飾語用的 ● public Class getDeclaringClass() 如果當前對象是另一個類的成員,則返回那個類的Class對象,否則為空。 8.3.3 Math類 Math類是一個最終類,類頭定義是:public final class Math extends Object。它包含了常用的科學計算方法。這些方法都是靜態方法,可以通過類名直接調用。下面我們列出其中常用的屬性和方法的定義: ● public static final double E ● public static final double PI 三角函數: ● public static double sin(double a) ● public static double cos(double a) ● public static double tan(double a) ● public static double asin(double a) ● public static double acos(double a) ● public static double atan(double a) 弧度、角度轉換如下: ● public static double toRadians(double angdeg) ● public static double toDegrees(double angrad) 代數函數: ● public static double exp(double a) ● public static double log(double a) ● public static double sqrt(double a) ● public static double ceil(double a) ● public static double floor(double a) ● public static double random() 以下3個方法都有其他數據類型的重載方法: ● public static int abs(int a) ● public static int max(int a,int b) ● public static int min(int a,int b) 8.3.4 String與StringBuffer類 Java提供了兩個用於字符串操作的類,一個是經常用到的String,另一個是StringBuffer。字符串類提供了豐富的字符串操作方法,程序員可以方便的使用這些常用的算法和操作,而不需要自己再重復編寫,這就是面向對象的好處。 1. 為什么要使用兩個類 String類用與處理那些值不會發生改變的字符串,以前程序中的String變量,全都是其取值沒有發生過變化的字符串。而StringBuffer類則用於那些可能發生變化的字符串的處理。例如,在程序中拼接字符串、從文件中讀取字符串等等。由於String類對象都是常量,它的處理效率要比StringBuffer類對象高得多,因此,讀者在編程時盡可能使用String類。 下面我們來看一個簡單的例子,它同時使用了String和StringBukffer, 例8.2 用兩種不同的字符串類來逆轉字符串 StringDemo.java測源程序如下: public class StringDemo{ public static void main(String[] args){ String palindrome="Dot saw I was Tod"; int len=palindrome.length(); StringBuffer dest=new StringBuffer(len); for(int i=(len-1);i>=0;i--){ dest.append(palindrome.charAt(i)); } System.out.println(dest.toString()); } } 在這個程序中,我們先創建了一個String類對象,並將字符串“Dot saw I was Tod”賦值給它,然后創建了一個和它一樣長的StringBuffer類對象。利用它來進行逆轉處理。這個程序的執行結果很有趣,實際上和輸入字符串幾乎是一樣的(除了第一個字母的大寫問題),即: doT sw I was toD 2. 對象的創建 一般情況下,創建一個String都是采用直接給一個String對象賦值的方法,其值用雙引號括起來,如: String palindrome=”Dot saw I was Tod”; 當然,也可以象創建其它對象那樣,新建一個String對象出來,Java為String提供了幾種比較常用的構造期。如,使用字符數組或者StringBuffer等,下面是一個使用字符數組創建String對象的例子: char[] helloArray={‘h’,’e’,’,’l’,’l’,’o’}; String helloString=new String(helloArray); System.out.println(hellostring); 3. String的常用方法 String的常用方法如下: ● public int length() 返回字符串長度 ● public char charAt(int index) 返回index位置的字符,index從0到length()-1 ● public void getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin) 這個方法是把字符串中的字符復制到一個字符數組中 ● public Boolean equals(Object anObject) 這是對Object類中同方法的重載 ● public int compareTo(String anotherString) 這是實現Serializable接口中的方法,如果實際字符串比形參字符串以字典排序時靠前,返回負數,相反時為正數。 ● public Boolean startsWith(String prefix) ● public Boolean endsWith(String suffix) 上面兩個方法分別判斷字符串是否以形參字符開始或結束。 ● public int indexOf(int ch) 該方法返回字符串中第一個出現形參所指示的字符的位置,如果沒有該字符,返回-1。 ● public int indexOf(int ch,fromIndex) 從fromIndex開始查找,返回第一個是ch字符的位置,或者返回-1。 ● public int lastIndexOf(int ch) 返回字符串中最后一個ch字符的位置或-1。 ● public String Substring(int beginIndex) 返回從當前字符串中的beginIndex開始形成的新字符串。 ● public String substring(int beginIndex,int endIndex) 返回從當前字符串截取的新字符串,beginIndex是開始位,endIndex是結束位減1。 ● public string concat(String str) 把形參字符串連接到當前字符串后,字符串的加法運算就是這個方法。 ● public String replace(char oldChar,char newChar) 把字符串中所有相同的某個字符換成另一個。 4. StringBuffer的常用方法 由於StringBuffer類是可變字符串,所有它的操作主要集中在對字符串的更改上,因此先介紹它的append()和insert()方法,這兩個方法都有多個重載方法,以實現不同的操作。 ● public StringBuffer append(String str) 從方法名就可以知道這是一個擴充字符串的方法,它的功能是把形參字符串加到當前字符串之后,形成一個新的可變字符串。例如: StringBuffer new StringBuffer(); s.append(“start”); s.append(“le”); 以上幾個語句的結果是得到一個含有“startle”的可變字符串。 ● public StringBuffer insert(int offset,String str) 這個方法是在當前字符串中插入形參字符串,形成一個新的可變字符串。其中形參offset是偏移量,它指示在何處插入,0<=offset<=length(). 下面介紹該類的其它一些常用方法: ● public StringBuffer delete(int start,int end) 刪除start(含)到end(不含)之間的字符。 ● public StringBuffer deleteCharAt(int index) 刪除指定位置的字符。 ● public StringBuffer replace(int start,int end,String str) 從start(含)到end(不含)之間的字符串以str代替。 ● public void setCharAt(int index,char ch) 改變指定位置的字符 ● public StringBuffer reverse() 使字符串逆轉 ● public int length() 返回字符個數 ● public int capacity() 返回容量,通常會大於等於length() ● public void setLength(int newlength) 改變字符個數,如果newLength大於原個數,則新添的字符都為空(“”)。相反,字符串中最好幾個字符將被刪除。形參newLength不能為負數。 ● public String substring(int start,int end) 提取子字符串,返回的是String類對象。 ● public String toString() 把可變字符串中內容變成String類對象。事實上在用println打印可變字符串內容時,就自動調用了該方法。 在String類和StringBuffer類中,有一點值得注意,許多方法中用到的形參是用來指示字符串中的位置,假設這個形參為int index,那么,字符串的第一個字符的index值為0,第二個字符為1,依此類推。 8.3.5 System類 系統類是一個獨特的類,它是一個final類,所有的方法都是用類變量調用的,換句話說,沒有人可以實例話一個System類。System類主要提供了標准輸入、輸出以及一些系統環境信息。 1. 標准輸入、輸出 ● public static final InputStream in——標准輸入 這個屬性是InputSream類的一個對象,關於InputStream類和下面的PrintStream類我們在java.io包中一並介紹,這些類都是關於輸入、輸出方面的,他們都有各自的屬性和方法,我們用過的read()就是InputStream類的方法,println()和print()就是PrintStream類的方法。 ● public static final PrintStream out——標准輸出 ● public static final PrintStream err——標准錯誤輸出 這些輸入、輸出屬性可以根據其所使用的參數來自動的轉換輸出格式,下面的例子利用標准輸出打印了幾種常見數據類型的數據,它們使用的是println方法,但系統可以根據不同類型以不同的方式打印這些數據的值。 例8.3 用標准輸出打印各種類型的對象 DataTypePrintTest.java的源程序如下: public class DataTypePrintTest{ public static void main(String[] args){ Thread objectData=new Thread(); String stringData="Java Mania"; char[] charArrayData={'a','b','c'}; int integerData=4; long longData=Long.MIN_VALUE; float floatDAta=Float.MAX_VALUE; double doubleData=Math.PI; boolean booleanData=true; System.out.println(objectData); System.out.println(stringData); System.out.println(charArrayData); System.out.println(integerData); System.out.println(longData); System.out.println(floatData); System.out.println(doubleData); System.out.println(booleanData); } } 其輸出結果為: Thread[Thread-0,5,main] Java Mania abc 4 -9223372036854775808 3.4028235E38 3.141592653589793 true 我們注意到,打印一個String類型變量,系統的動作就是打印出它的內容,而打印一個Thread型變量,則系統打印它的格式為: 類名[名稱,優先級,組] 2.系統環境信息 System類提供了一個方法用來返回系統環境信息: Public static Properties getProperties(argument); Java虛擬機維護了一系列系統環境信息,它們都是以“鍵名/值”對的形式出現的,一旦Java虛擬機啟動之后,系統就自動將這些變量初始化,其中包含了與運行環境相關的很多信息。 另外,System類提供的與系統環境信息相關的方法還有: ● public static String setProperty(String key,String value); 設置系統變量的值,key為鍵名,value為鍵值。 ● public static Properties getPorperties(); 返回所有的系統環境環境。 下面看一個例子,假設有一文本文件,叫myProperties.txt,其中只有一行: subliminal.message=Buy Java Now! 我們利用這個文件來設置變量,它的名字叫做subliminal,其取值就是文本文件中存貯的內容。 3.其它有用方法 System類有許多方法,用這些方法可以管理Java虛擬機的運行和獲得虛擬機的運行信息,下面是該類的幾個方法,它們可以反映System類的一些功能。 ● public static long currentimeMillis() 返回系統時間,單位毫秒。 ● public static void exit(int status) 在用戶的程序還未執行完之前,強制關閉Java虛擬機,並把狀態信息status傳遞給操作系統,status非零時,表示非正常退出 ● public static void ge() 運行垃圾收集器 以上的內容可以讓我們對System類的內容有一定的了解,這個類中的屬性和方法都與系統有關,而且這個類的許多方法借用了其它類的方法。 8.3.6 數據類型類 每一類簡單數據類型都對應着一個數據類型類,例如,int對應着Integer類,double對應着Double類,這些類能把一個簡單數據封裝成一個類。某些場合必須使用這種數據類型類,如后面的集合類,它的成員必須是類,而不能是簡單的變量。而且使用這些類能完成簡單變量不能完成的工作,如將一個數字字符串轉化成一個整數等。下面我們就以Integer類來說明這些類的某些方法。 ●MAX_VALUE和MIN_VALUE規定了int類型量的最大值和最小值。 ●構造函數:public Integer(int value)和public Integer(String s)分別把數字和數字字符串封裝成Integer類。 ● 下面幾個方法是把當前數據類型類的對象所對應的int量轉化成某種基本數據類型值: public int intValue() public long longValue() public double doubleValue() ● 下面是數字字符串和數字之間的轉換: public String toString() public static int parseInt(String s) ● public static static Integer valueOf(String s)方法把s轉化成Integer類對象。 8.4 關於Java的技術文檔 上面的內容是我們對包中的內容有了一定的了解,這一節研究JavaDOC中的類庫。 在下載完j2sdk-1_3_1-doc后,找到它下面的docs文件夾,打開index文件(HTML文件),找到API&Language Documentation下的Java2 Platfrom API Specificaion,然后選擇需要的那個包,進而查看類、接口等內容。或者直接進入docs文件夾下的api文件夾,打開index(HTML文件),也可以進入選擇包的界面。 選擇一個包后,可以看到包的名稱以及簡單描述,然后是包中的內容,分為interface summary,class summary,exception summary和error summary等,如果想看包中各類的繼承結構,可以選擇最上面的菜單中的tree,就可以了解包中的總體結構。當選擇一個類進入后,可以看到如下的內容(Double類的說明): java.lang //包名 Class.Double //類名 Java.lang.Object //繼承結構:java.lang包中的Double類的直接父類 | //是java.lang中的Number類 +--java.lang.Number //Number類的父類是java.lang中的Object類 | +--java.lang.Double All Implemented Interfaces: //這個類實現的接口 Comparable,Serializable 然后就是屬性、方法、構造函數的概述表(summary),最后是屬性、方法、構造函數的詳細說明。 |