java簡要提醒

組件在容器中的佈局
當我們把組件添加到容器中時,希望控制組件在容器中的位置。在默認情況下,每個容器中都有佈局管理器。如果容器的默認佈局管理器 不能滿足用戶的需要,用戶可以使用別的佈局管理器來代替它。Java的java.awt包中定義了5種佈局類,每個佈局類的實例 對應一種佈局策略,這5個佈局類分別是:FlowLayout、BorderLayout、CardLayout、GridLa yout和GridBagLayout。其中GridBagLayout是最複雜、功能最強大的一種。
1、FlowLayout佈局
FlowLayout是Panel型容器和Applet型容器默認使用的佈局。如果不專門爲Panel和Applet指定佈局, 則它們就使用FlowLayout佈局。
FlowLayout對應的佈局非常簡單,遵循這種佈局的容器將其中的組件按照加入的先後順序從左向右排列,一行排滿之後就轉到 下一行繼續從左至右排列,每一行中的組件都居中排列。在組件不多時,使用這種策略非常方便,但是當容器內的組件元素增多時,就顯 得高低不平。以前的例子使用的就是這種佈局。
對於使用FlowLayout的容器,加入組件使用簡單的add(組件名)命令即可,這些組件將順序地排列在容器中。有時由於F lowLayout的佈局能力有限,程序會採用容器嵌套的方法,這個被嵌套的容器組件可以有自己的組件和自己的佈局,使整個容器 的佈局達到應用的需求。
對於一個原本不使用FlowLayout佈局的容器,若需要將其佈局策略改爲FlowLayout,可以使用如下的語句:set Layout(new FlowLayout());
setLayout()方法是所有容器的父類Container的方法,用於爲容器設定佈局。
FlowLayout類有3個構造方法:
public FlowLayout()        
public FlowLayout(int alignment)
public FlowLayout(int alignment,int horizontalGap,int verticalGap)
alignment參數的值必須是FlowLayout.LEFT、FlowLayout.CENTER或FlowLayout .RIGGHT。horizontalGap和verticalGap參數指定了組件間隔距離(以像素爲單位)。如果用戶沒有指 定間隔值,FlowLayout將自動指定其值爲5。
2、BorderLayout佈局
BorderLayout也是一種簡單的佈局策略,它把容器內的空間簡單地劃分爲東、西、南、北、中5個區域,每加入一個組件都 應該指明把這個組件加到哪個區域中。
BorderLayout只能指定5個區域位置,如果容器中需要加入超過5個組件,就必須使用容器的嵌套或改爲其他的佈局策略。 (組件可以不足5個)
當用戶向使用BorderLayout佈局管理器的容器中加入組件時,用戶必須使用兩個參數的add()方法,而且第一個參數必 須爲“North”、“South”、“East”、“West”或“Center”。如果用戶使用一個參數的add()方法或 指定的第一個參數無效,那麼該組件將不能顯示出來。
在默認的情況下,BorderLayout將使它管理的組件之間沒有空隙,用戶可以用下面的構造方法指定間隙:public BorderLayout(int horizontalGap,int verticalGap)
舉例:E13、Example12_1
3、CardLayout佈局
使用CardLayout的容器可以容納多個組件,但是實際上同一時刻容器只能從這些組件中選出一個來顯示,就像一疊紙牌每次只 能顯示最上面的一張一樣,這個被顯示的組件將佔據所有的容器空間。使用CardLayout的一般步驟如下(假設容器名爲con ):
(1)創建CardLayout對象作爲佈局。如:Mycard = new CardLayout();
(2)使用容器的setLayout()方法爲容器設置佈局。如:con.setLayout(Mycard);
(3)調用容器的add()方法將組件加入容器。con.add(組件代號,組件);組件代號是另外給的,和組件的名字沒有必然 聯繫。
(4)創建的佈局Mycard用CardLayout類提供的show()方法,更據容器名字con和其中的組件代號顯示這一組 件:Mycard.show(con,組件代號);或按組件加入容器的順序顯示組件,如:first(con)方法顯示con中 的第一個組件、last(con)方法顯示con中的最後一個組件、next(con)顯示下一個組件、previous(co n)顯示前一個組件等(最先加入con的是“卡片”式的第一張,依次排序)。
舉例:E14
4、GridLayout佈局
GridLayout是使用較多的佈局編輯器,其基本佈局策略是把容器劃分成若干行乘若干列的網格區域,組件就位於這些劃分出來 的小格中。GridLayout比較靈活,劃分多少網格由程序自由控制,而且組件定位也比較精確,使用GridLayout佈局 編輯器的一般步驟如下:
創建GridLayout對象作爲佈局,指定劃分網格的行數和列數,並使用容器的setLayout()方法爲容器設置這個佈局 編輯器:setLayout(new GridLayout(行數,列數))。
調用容器的方法add()將組件加入容器,組件從左到右排滿第一行之後再排第二行,依次類推。每個網格中都必須填入組件,如果希 望某個網格爲空白,可以爲它加入一個空的標籤:add(new Label())。
舉例:E15(Example12_3)
由於GridLayout佈局中每個網格都是相同大小並且強制組件與網格的大小相同,容器中的每個組件也都是相同的大小,顯得很 不自然。爲了克服這個缺點,可以使用容器嵌套。如:一個容器使用GridLayout佈局,將容器分爲三行一列的網格;然後可以 把另一個容器添加到某個網格中,而添加的這個容器又可以設置爲GridLayout佈局,把自己分爲若干網格。利用這種方法,可 以設計出符合一定需要的佈局。
例題:E16(Example12_4)
5、GridBagLayout佈局
GridBagLayout是AWT提供的最靈活、最複雜的佈局管理器。GridBagLayout將組件以多行多列放置,允許 指定的組件跨多行或多列。如果用戶增大Applet的窗口,用戶會發現最後一行會佔有所有新的垂直方向的空間,所有新的水平方向 的空間將被所有的列分割。這個改變尺寸的動作是以Applet分配給GridBagLayout中單個組件的權爲依據的。用戶還 會看到每個組件會佔據儘可能多的空間,這個動作也是由Applet指定的。暫略討論。
6、null佈局與setBounds方法
我們可以把一個容器的佈局設置爲null佈局(空佈局)。
setBounds(int a,int b,int width,int height)方法是所有組件都擁有的一個方法,組件調用該方法可以設置本身的大小和在容器中的位置。
假設p是某個容器:p.setLayout(null);把p的佈局設置爲空佈局。
向空佈局的容器p添加一個組件c需要兩個步驟,首先使用add(c)方法向容器添加組件,然後組件c再調用setBounds( int a,int b,int width,int height)方法設置該組件在容器中的位置和本身的大小。組件都是一個矩形結構,方法中的參數a、b是組件c的左上角在容器中 的位置座標;weidth、height是組件c的寬和高。
舉例:E17(Example12_6)
使用佈局管理器的基本規則:
(1)用戶要求儘量使用所有的空間來顯示組件,可以考慮使用BorderLayout和GridBagLayout。如果使用B orderLayout,用戶應該將佔用空間最大的組件放在中心部位。如果使用GridLayout,用戶需要爲組件設置限制條 件。
(2)用戶需要在緊湊的一行中以組件的自然尺寸顯示較少組件時,用戶可以考慮用面板容納組件,並使用面板的缺省佈局管理器Flo wLayout。
(3)用戶需要在多行或多列中顯示一些同樣尺寸的組件,GridLayout最適合此情況。如果有必要的話,可以使用面板來容納 組件。
畫布
畫布是一種通用組件,本身不具有任何功能,也不能處理任何事件。它是一個可以在上面繪畫的簡單組件,不是容器。Java.awt 包中的類Canvas負責創建畫布對象。創建畫布對象的常用方法是用Canvas的子類來創建畫布對象,並在子類中重寫父類的方 法:paint。需要注意的是:一定要在創建畫布的類的構造方法中給出畫布的尺寸(單位爲像素)。
舉例:E18(Example11_3)
在上例中,Mycanvas類中的構造方法必須通過getSize()方法得到它的大小,當使用getSize()方法時,該類 中的getPreferredSize()方法會自動被執行,可以在這個方法的方法體中通過使用Dimension類(在jav a.awt包中)給出畫布的大小。
使用AWT組件繪圖
使用AWT組件中的Graphics類,除了可以顯示字符串以外,還可以在應用程序的框架窗口中繪圖。在Graphics類中定 義了豐富的方法來繪製各種圖形,常用的一些方法有:
1、顯示字符串與字符數組
drawString(String s, int x, int y);
在屏幕上從由x和y參數所指定的位置上開始往右顯示字符串。
drawChars(char data[ ], int offset, int length, int x, int y);
x和y參數指定顯示字符的位置,offset和length參數指定數組中要顯示的字符。
舉例:E19(Example17_2)
2、繪製直線
drawLine(int x1, int y1, int x2, int y2);
3、繪製長方形
drawRect(int x, int y, int width, int height);
x和y參數指定長方形左上角的位置,width和length參數指定長方形的寬度和高度。
fillRect(int x, int y, int width, int height);
drawRect方法只畫出長方形的輪廓,而fillRect方法畫出長方形並填充它。
drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight);
畫圓角矩形,arcWidth和arcHeight參數指定矩形圓角的尺寸。當width=height=arcWidth=a rcHeight時爲圓環。
4、畫橢圓
drawOval(int x, int y, int width, int height);
x和y表示橢圓距x軸和y軸的距離,單位爲像素;參數width、height表示橢圓的寬和高。當width=height時 爲圓環。
fillOval(int x, int y, int width, int height);
fillOval方法使用setColor方法所指定的顏色畫着色的橢圓。
5、繪製圓弧
drawArc(int x, int y, int width, int height, int starAngle, int arcAngle); 
starAngle和arcAngle表示圓弧的開始角和圓弧對應的圓心角。
fillArc(int x, int y, int width, int height, int starAngle, int arcAngle);
fillOval方法使用setColor方法所指定的顏色畫填色的圓弧。
舉例:E20
      E21(Example12_2)
處理選擇框事件
當用戶把選擇框從未選中狀態變成選中狀態或從選中狀態變成未選中狀態時就發生了一個選擇框事件。
對於選擇框這個事件源,它有一種事件,就是選擇框的選擇情況的變化。這種事件源獲得監視器的方法是addItemListene r()。處理該事件的接口是ItemListener,接口中的方法是itemStateChanged(ItemEvent e)。選擇框這種事件的類型是ItemEvent類型,即當從未選中到選中或從選中到未選中後,Java包Java.awt.e vent中的類ItemEvent自動創建了一個事件對象。
ItemEvent類中有一個重要的方法:getItemSelectable();它返回引發選中狀態變化事件的事件源。也就 是說,對於ItemEvent事件類型的事件,如果想尋找事件源,需使用getItemSelectable()方法。
舉例:E22(Example13_4)
      E23(Example13_3)
處理下拉式列表事件
下拉式列表實際上就是一種選擇控件。當用戶在選擇控件中選出某個選項時就發生了一個選擇控件上的事件。
對於選擇控件這個事件源,它有一種事件,就是選擇控件的選擇情況的變化。這種事件源獲得監視器的方法是addItemListe ner()。處理該事件的接口是ItemListener,接口中的方法是itemStateChanged(ItemEven t e)。選擇控件這種事件的類型是ItemEvent類型,即當從選擇控件選中選項時,Java包Java.awt.event中 的類ItemEvent自動創建了一個事件對象。
ItemEvent類中有一個重要的方法:getItemSelectable();它返回引發選中狀態變化事件的事件源。也就 是說,對於ItemEvent事件類型的事件,如果想尋找事件源,需使用getItemSelectable()方法。
舉例:E24(Example14_2)
處理列表事件
滾動列表事件源有兩種事件:一種是鼠標雙擊某個選項,另一種是鼠標單擊某個選項。對於第一種事件事件源獲得監視器的方法是add ActionListener()。處理該事件的接口是ActionListener,接口中的方法是actionPerfor med(ActionEvent e)。這種事件的類型是ActionEvent,即當從列表中雙擊某個選項時,Java包Java.awt.event中的類A ctionEvent自動創建了一個事件對象。
ActionEvent類中有一個重要的獲得事件源方法:getSource()。
對於第二種事件源獲得監視器的方法是:addItemListener()。處理該事件的接口是ItemListener,接口 中的方法是itemStateChanged(ItemEvent e)。選擇控件這種事件的類型是ItemEvent類型,即當單擊了選項時,Java包Java.awt.event中的類It emEvent自動創建了一個事件對象。
ItemEvent類中有一個重要的獲得事件源方法:getItemSelectable()。它返回引發選中狀態變化事件的事 件源。也就是說,對於ItemEvent事件類型的事件,如果想尋找事件源,需使用getItemSelectable()方法 。
舉例:E25(Example14_4)
窗口
1、建立窗口
舉例:E26(Example15_1)
      E27(Example15_3)
2、向窗口增加菜單
舉例:E28(Example15_4)
3、處理菜單項上的事件
菜單項事件源有1種事件:用鼠標單擊某個選項。
事件源獲得監視器的方法是:addActionListener()。處理該事件的接口是ActionListener,接口中 的方法是actionPerformed(ActionEvent e)。這種事件的類型是ActionEvent,即當單擊菜單項某項時,java包java.awt.event中的類Acti onEvent自動創建了一個事件對象。
ActionEvent類中有一個重要的獲得事件源的方法:getSource()。
舉例:E29(Example15_5)
      E30(Example15_6)
4、增加菜單分割線和嵌入子菜單
要增加菜單分割線,只需要使用Menu類中的addSeparator()方法。
菜單項本身還可以是一個菜單,這樣的菜單項稱爲子菜單。
舉例:E31(Example15_9)
對話框
1、普通對話框
對話框必須依賴一個窗口,因此要建立對話框,必須首先建立一個創建窗口的窗口類。對話框的默認佈局是BorderLayout布 局,在創建對話框時必須有對話框大小的設置,在其構造方法中要通過使用super()方法調用父類的相應的構造方法。
舉例:E32(Example16_1)
在上面的例子中,創建的對話框是可見的。但我們希望在它依賴的窗口內設置按鈕或菜單,通過菜單項事件或按鈕事件隨時打開或關閉對 話框。另外,我們還希望對話框能完成某些任務。
舉例:E33(Example16_2)
2、文件對話框
FileDialog是Dialog類的子類,它創建的對象稱爲文件對話框。文件對話框是一個打開文件和保存文件的對話框窗口。 文件對話框也必須依附一個窗口(Frame)對象。
文件對話框僅僅提供了一個文件操作的界面,要真正實現對文件的操作,要學習文件的輸入輸出流。
舉例:E34(Example16_3)
輸入輸出流
I/O流提供一條通道程序,可以使用這條通道把源中的字節序列送到目的地。Java的I/O流庫提供大量的流類(在包java. io中)。其中,所有輸入流類都是InputStream(輸入流)抽象類的子類,而所有輸出流都是OutputStream( 輸出流)抽象類的子類。
一、FileInputStream類
如果用戶的文件讀取需求比較簡單,那麼用戶可以使用FileInputStream類,該類是從InputStream中派生出 來的簡單輸入類。該類的所有方法都是從InputStream類繼承來的。爲了創建FileInputStream類的對象,用 戶可以調用它的構造器:
FileInputStream(String name);//參數爲文件名
FileInputStream(File file);//參數爲文件對象
1.使用文件輸入流讀取文件
文件輸入流(輸入流的子類)提供對文件的存取。爲了讀取文件,使用文件輸入流構造器來打開一個到達該文件的輸入流。例如,爲了讀 取一個名爲myfile.dat的文件,建立一個文件輸入流對象如下:FileInputStream istream=new FileInputStream(“myfile.dat”);
或File f=new File(“myfile.dat”);FileInputStream istream=new FileInputStream(f);
 File類有兩個常用的構造方法:
 File(String s);//s確定文件的名字,並且該文件和應用程序在同一目錄下。
 File(String directory,String s);//directory確定文件的目錄,s確定文件的名字。
 2.處理I/O異常
 使用文件輸入流構造器建立通往文件的輸入流時,可能會出現異常,Java生成一個出錯信號,它使用一個IOExce ption(IO異常)對象來表示這個出錯信號。程序必須使用一個catch(捕獲)塊檢測並處理這個異常。爲了把一個文件輸入 流對象與一個文件關聯起來,使用類似於下面所示的代碼:
    try { FileInputStream ins = new FileInputStream(“myfile.dat”);}
 catch(IOException e){ System.out.println(“File read error:”+e);}
 由於I/O操作對於錯誤特別敏感,所以許多其他的流類構造器和方法也產生I/O異常。同樣必須按上述程序段所示的相 同方式捕獲(catch)或處理這些異常。
 3.從輸入流中讀取字節
 輸入流的唯一目的是提供通往數據的通道,程序可以通過這個通道讀取數據,read()方法給程序提供一個從輸入流中 讀取數據的基本方法。
 int read();//read()方法從輸入流中讀取單個字節的數據。該方法返回字節值(0~255之間的一個整數),如果該方法 到達輸入流的末尾,則返回-1。
 read方法還有其他一些形式。這些形式能使程序把多個字節讀到一個字節數組中:
 int read(byte b[ ]);//返回被讀取的字節個數,如果到達輸入流的末尾,則返回-1。
 int read(byte b[ ],int off,int len);//返回被讀取的字節個數,如果到達輸入流的末尾,則返回-1。其中off參數指定read方法把數據存放在字節數組 b中的什麼地方;len參數指定該方法就讀取的最大字節數。
 4.關閉流
 雖然Java在程序結束時自動關閉所有打開的流,但是當使用完流後,顯示地關閉任何打開的流是一個良好的習慣。一個 被打開的流可能會用盡系統資源,如果沒有關閉那些被打開的流,那麼在這個或另一個程序試圖打開新的流時,可能得不到資源。關閉輸 出流的另一個原因是把該流緩衝區的內容沖洗掉(在操作系統把程序所寫到輸入流上的那些字節保存到磁盤上之前,內容被存放在內存緩 衝區中)。
 通過調用close()方法,可以保證操作系統把流緩衝區的內容寫到它的目的地。
 舉例:E35(Example20_2)
二、FileOutputStream類
與FileInputStream類相對應的類是FileOutputStream類。FileOutputStream類提供 了基本的文件寫入能力。除了從OutputStream類繼承來的方法以外,FileOutputStream類還有3個構造器 :
FileOutputStream(String name);//使用給定的文件名name創建一個FileOutputStream對象
FileOutputStream(File file);//使用File對象創建FileOutputStream對象
FileOutputStream(FileDescriptor fdobj);//使用FileDescriptor對象創建FileOutputStream對象
可以使用write()方法把字節發送給輸出流:
public void write(byte b[ ]);//寫b.length個字節到輸出流
public void write(byte b[ ],int off,int len);//從給定字節數組中起始於偏移量off處寫len個字節到輸出流,參數b是數據;off是數據的起始偏移量;len 是要輸出的字節數。
舉例:E36(Example20_3)
三、FileReader類和FileWriter類
與FileInputStream類和FileOutputStream類等價的讀取器是FileReader類和FileWr iter類,它們分別是InputStream和OutputStream的子類。其構造方法分別是:
FileReader(String filename);
FileWriter(String filename);
使用這兩個類時需要處理FileNotFoundException異常。
下例是一段創建FileReader對象的代碼,可以使用該對象讀取名爲Student.txt的文件。
FileReader file = new FileReader(“Student.txt”);
Student.txt文件存放了一個學生名單,每個姓名佔一行。如果我們想讀取名字,那麼每次必須讀取一行,但FileRea der類沒有提供這種方法,所以我們必須把這個流(對象)再接到另外一個流上,從後一個流中讀取名單。Java提供了名爲Buf feredReader的類,構造方法是:BufferedReader(Reader in);//能夠讀取文本行,方法是readLine()。
通過向BufferedReader傳遞一個Reader對象(如FileReader的實例),來創建一個BufferedR eader對象,代碼如下:
BufferedReader in = BufferedReader(new FileReader(“Student.txt”));
然後再從流in中讀取學生名單。
舉例:E37(Example20_4)
下例是一段創建FileWriter對象的代碼,可以使用該對象寫名hello.txt的文件。
FileWriter tofile = new FileWriter(“hello.txt”);
我們用Java的BufferedWriter類創建一個流,接到流tofile上,然後使用BufferedWriter類的 方法:write(String s,int off,int len);把字符串s寫到hello.txt中。
BufferedWriter out = new BufferedWriter(new FileWriter(“hello.txt”));
out.write(“how are you”,0,s.length());
但out.write(“how are you”,0,s.length())只是將字符串“how are you”寫入了緩衝區,如想寫入到文件,必須再執行語句:out.flush();將緩衝區的字符串寫入文件hello.txt 。
舉例:E38(Example20_5)
四、使用文件對話框打開和保存文件
在學習了流之後,我們可以使用文件對話框來打開和保存文件了。
在下例中我們把一個文件的內容顯示在一個文本區內,並把文本區的內容保存到硬盤的某個文件夾中去。
舉例:E39(Example20_7)
在下例中我們使用文件對話框打開本地機器上一個可執行文件。要執行一個本地機上的可執行文件時,可以使用java.lang包中 的Runtime類。首先使用Runtime類聲明一個對象:
Runtime ec;
然後使用該類的靜態方法getRuntime()創建這個對象:
ec = Runtime.getRuntime();
ec可以調用exec(String command)方法打開本地機的可執行文件。
舉例:E40(Example20_8)
五、數據流
DataInputStream類和DataOutputStream類創建的對象被稱爲數據輸入流和數據輸出流。它們允許程序 按與機器無關的風格讀取Java原始數據。即當我們讀取一個數值時,不必再關心這個數值應當是多少個字節。
DataInputStream(InputStream in):將創建的數據輸入流指向一個由參數in指定的輸入流,以便從後者讀取數據(按與機器無關的風格讀取)。
DataOutputStream(OutputStream out):將創建的數據輸出流指向一個由參數out指定的輸出流,然後通過這個數據輸出流把Java數據類型的數據寫到輸出流o ut。
數據流的部分方法:
close();關閉流
readBoolean();讀取一個布爾值
readByte();讀取一個字節
readChar();讀取一個字符
readDouble();讀取一個雙精度浮點值
readFloat();讀取一個單精度浮點值
readInt();從文件中讀取一個int值
readLong();讀取一個長型值
readShort();讀取一個短型值
readUnsignedByte();讀取一個無符號字節
readUnsignedShort();讀取一個無符號短型值
readUTF();讀取一個UTF字符串
SkipBytes(int n);跳過給定數量的字節
writeBoolean(boolean v);把一個布爾值作爲單字節值寫入
writeBytes(String s);寫入一個字符串
writeChars(String s);寫入字符串
writeDouble(double v);寫入一個雙精度浮點值
writeFloat(float v);寫入一個單精度浮點值
writeInt(int v);一個int值
writeLong(long v);一個長型值
writeShort(int v);一個短型值
writeUTF(String s);寫入一個UTF字符串
舉例:E41(Example20_12)
      E42(Example20_13)
使用StringTokenizer類分析字符串
有時我們需要分析字符串並將字符串分解成可被獨立使用的單詞,這些單詞叫做語言符號。例如,對於字符串“We are Students”,如果我們把空格作爲了該字符串的分隔符,那麼該字符串有3個單詞(語言符號)。而對於字符串“We,are ,Student”,如果我們把中文逗號作爲了該字符串的分隔符,那麼該字符串有3個單詞(語言符號)。
當我們分析一個字符串並將字符串分解成可被獨立使用的單詞時,可以使用java.util包中的StringTokenizer 類,該類有兩個常用的構造方法:
StringTokenizer(String s):爲字符串s構造一個分析器。使用默認的分隔符集合,即空格符(若干個空格被看做一個空格)、換行符、回車符、Tab符、進 紙符。
StringTokenizer(String s,String delim):爲字符串s構造一個分析器。參數delim中的字符被作爲分隔符。例如:
StringTokenizer fenxi = new StringTokenizer(“we are student”);或
StringTokenizer fenxi = new StringTokenizer(“we,are,student”,“,;”);
我們把一個StringTokenizer對象稱作一個字符串分析器。一個分析器可以使用nextToken()方法逐個獲取字 符串中語言符號(單詞),每當調用nextToken()時,都將在字符串中獲得下一個語言符號。通常用while循環來逐個獲 取語言符號,爲了控制循環,我們可以使用StringTokenizer類中的hasMoreTokens()方法,只要字符串 中還有語言符號,該方法就返回true,否則返回false。另外我們還可以調用countTokens()方法得到字符串一共 有多少個語言符號。
舉例:E43(Example5_7) 
      E44(Example8_6)
      E45(Example20_6)
Java的多線程機制
以往我們開發的程序都是單線程的,即一個程序只有一條從頭至尾的執行線索。然而現實世界中的很多過程都是具有多條線索同時動作的 特性。例如:我們可以一邊看電視一邊活動胳膊。再如一個網絡服務器可能需要同時處理多個客戶機的請求等。Java語言的一大特性 就是內置對多線程的支持。
一、Java中的線程
1.程序、進程和線程
程序是一段靜態的代碼,它是應用軟件執行的藍本。
進程是程序的一次動態執行過程,它對應了從代碼加載、執行至執行完畢的一個完整過程,這個過程也是進程本身從產生、發展至消亡的 過程。如果把上課比作一個進程,那麼上課鈴是進程的開始,下課鈴是進程的結束。
線程是比進程更小的執行單位。一個進程在其執行過程中,可以產生多個線程,形成多條執行線索,每條線索,即每個線程也有它自身的 產生、存在和消亡的過程,也是一個動態的概念。就如上課開始後,可以有多個不同的“線程”,如老師的講解、學生的聽講。每個進程 都有一段專用的內存區域,而線程間可以共享相同的內存單元(包括代碼和數據),並利用這些共享單元來實現數據交換、實時通信與必 要的同步操作。
2.線程的狀態與生命週期
每個Java程序都有一個缺省的主線程。對於應用程序,主線程是main()方法執行的線索。對於applet,主線程指揮瀏覽 器加載並執行Java小程序。要想實現多線程,必須在主線程中創建新的線程對象。Java語言使用Thread類及其子類的對象 來表示線程。新建的線程在它的一個完整的生命週期中通常要經歷如下的5種狀態:
(1)新建:當一個Thread類及其子類的對象被聲明並創建時,新生的線程對象處於新建狀態。此時它已經有了相應的內存空間和 其他資源。
(2)就緒:處於新建狀態的線程被啓動後,將進入線程隊列排隊等待CPU服務,此時它已經具備了運行的條件,一旦輪到它來享用C PU資源時,就可以脫離創建它的主線程獨立開始自己的生命週期了。
(3)運行:當就緒狀態的線程被調度並獲得處理器資源時,便進入運行狀態。每一個Thread類及其子類的對象都有一個重要的r un()方法,當線程對象被調度執行時,它將自動調用本對象的run()方法,從第一句開始順序執行。run()方法定義了這個 線程的操作和功能。
(4)阻塞:一個正在執行的線程如果在某些特殊情況下,如被人爲掛起或需要執行費時的輸入輸出操作時,將讓出CPU並暫時中止自 己的執行,進入阻塞狀態。阻塞時它不能進入排隊隊列,只有當引起阻塞的原因被消除時,線程纔可以轉入就緒狀態,重新進入到線程隊 列中排隊等待CPU資源,以便從原來終止處開始繼續運行。
(5)死亡:處於死亡狀態的線程不具有繼續運行的能力。線程死亡的原因有二,一個是正常運行的線程完成了它的全部工作,即執行完 了run()方法的最後一個語句並退出,另一個是線程被提前強制性地終止。
3.線程調度與優先級
處於就緒狀態的線程首先進入就緒隊列排隊等候處理器資源,同一時刻在就緒隊列中的線程可能有多個。多線程系統會給每個線程自動分 配一個線程的優先級,任務較緊急的重要線程,其優先級就較高;相反則較低。在線程排隊時,優先級高的線程可以排在較前的位置,能 優先享用到處理器資源,而優先級較低的線程則只能等到排在它前面的高優先級線程執行完畢之後才能獲得處理器資源。對於優先級相同 的線程,則遵循隊列的“先進先出”原則,即先進入就緒狀態排隊的線程被優先分配到處理器資源,隨後才爲後進入隊列的線程服務。
當一個在就緒隊列中排隊的線程被分配到處理器資源而進入運行狀態之後,這個線程就稱爲是被“調度”或被線程調度管理器選中了。線 程調度管理器負責管理線程排隊和處理器在線程間的分配,一般都配有一個精心設計的線程調度算法。在Java系統中,線程調度依據 優先級基礎上的“先到先服務”原則。
二、Java的線程類與Runnable接口
1.Thread類
Thread類綜合了Java程序中一個線程需要擁有的屬性和方法,主要有:
(1)構造函數
Thread類的構造函數有多個,其對應的操作有如下兩種。
public Thread():創建一個線程對象。
public Thread(Runnable target):創建線程對象,參數target稱爲被創建線程的目標對象。創建目標對象target的類負責實現Runnab le接口,給出該接口中run()方法的方法體,在方法體中給出該線程的操作和功能。
利用構造函數創建新線程對象之後,這個對象中的有關數據被初始化,從而進入線程的生命週期的第一個狀態(新建)。
(2)線程優先級
Thread類有3個有關線程優先級的靜態常量:MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORI TY。其中MIN_PRIORITY代表最小優先級,通常爲1。MAX_PRIORITY代表最高優先級,通常爲10。NORM _PRIORITY代表普通優先級,缺省數值爲5。
對應一個新建線程,系統會遵循如下的原則爲其指定優先級:
新建線程將繼承創建它的父線程的優先級。父線程是指執行創建新線程對象語句的線程,它可能是程序的主線程,也可能是某一個用戶自 定義的線程。一般情況下,主線程具有普通優先級。另外,用戶可以通過調用Thread類的setPriority(int a)方法來修改系統自動設定的線程優先級,使之符合程序的特定需要。a取值是:
Thread. MIN_PRIORITY,Thread. MAX _PRIORITY,Thread. NORM _PRIORITY。
(3)其他主要方法
啓動線程的start()方法。start()方法將啓動線程對象,使之從新建狀態轉入就緒狀態並進入就緒隊列排隊。
定義線程操作的run()方法。Thread類的run()方法與Runnable接口中的run()方法的功能和作用相同,都 用來定義線程對象被調度之後所執行的操作,都是系統自動調用而用戶程序不得引用的方法。系統的Thread類中,run()方法 沒有具體內容,所以用戶程序需要創建自己的Thread類的子類,並重寫run()方法來覆蓋原來的run()方法。
使線程暫時休眠的sleep()方法。線程的調度執行是按照其優先級的高低順序進行的,當高級線程不完成,即未死亡時,低級線程 沒有機會獲得處理器。有時,優先級高的線程需要優先級低的線程做一些工作來配合它,或者優先級高的線程需要完成一些費時的操作, 此時優先級高的線程應該讓出處理器,使優先級低的線程有機會執行。爲達到這個目的,優先級高的線程可以在它的run()方法中調 用sleep()方法來使自己放棄處理器資源,休眠一段時間。休眠時間的長短由sleep()方法的參數決定。
sleep(int millsecond):millsecond是以毫秒爲單位的休眠時間。
sleep(int millsecond,int nanosecond):nanosecond是以納秒爲單位的休眠時間。
中止線程的yield()方法。程序中需要強制終止某線程的生命週期時可以使用yield()方法。
判斷線程是否未消亡的isAlive()方法。在調用yield()方法終止一個線程之前,最好先用isAlive()方法檢查 一下該線程是否仍然存活,殺死不存在的線程可能會造成系統錯誤。Thread類還有一個靜態方法:currentThead() ,判斷當前正在佔有CPU的那個線程。
2.Runnable接口
Runnable接口只有一個方法run(),所有實現Runnable接口的用戶類都必須具體實現這個run()方法,爲它提 供方法體並定義具體操作。Runnable接口中的run()方法是一個較特殊的方法,它可以被運行系統自動識別和執行。具體的 說,當線程被調度並轉入運行狀態時,它所執行的就是run()方法中規定的操作。所以,一個實現了Runnable接口的類實際 上定義了一個主線程之外的新線程的操作,而定義新線程的操作和執行流程,是實現多線程應用的最主要和最基本的工作之一。
三、如何在程序中實現多線程
在程序中實現多線程有兩個途徑:創建Thread類的子類或實現Runnable接口。無論採用哪種途徑,程序員可以控制的關鍵 性操作有兩個:
(1)定義用戶線程的操作,即定義用戶線程的run()方法。
(2)在適當時候建立用戶線程實例。
1.用Thread類的子類創建線程
在這個途徑中,用戶程序需要創建自己的Thread類的子類(Thread在java.lang包中),並在子類中重新定義自己 的run()方法,該run()方法中包含了線程的操作。這樣程序需要建立自己的線程時,只需要創建一個已定義好的Thread 子類的實例就可以了。當你創建的線程調用start()方法開始運行時,run()方法就被自動執行。
舉例:E46(Example19_1)
2.實現Runnable接口
舉例:E47(Example19_2)
在具體應用中,採用哪種方法來構造線程體要視具體情況而定。通常,當一個線程已繼承了另一個類,而想在該線程中再創建一個新的線 程時,就應該用第二種方法來構造,即實現Runnable接口。
小應用程序實際上是瀏覽器的一個線程,這個線程由瀏覽器啓動執行,瀏覽器自動調用執行小應用程序中的init()、start( )方法等。因此要在小應用程序中創建一個新的線程,最好把新線程的啓動放在小程序的start()方法中。
舉例:E48(Example19_4)
四、Thread類的靜態方法sleep()
由於sleep()方法可以被類名直接調用,因此當需要推延程序的執行時可以使用如下語句:Thread. sleep(int time);
舉例:E49(Example19_8)
五、線程同步
Java使我們可以創建多個線程,在處理多線程問題時,我們必須注意這樣一個問題:當兩個或多個線程同時訪問同一個變量,並且一 個線程需要修改這個變量。我們應對這樣的問題作出處理,否則可能發生混亂,比如一個工資管理負責人正在修改僱員的工資表,而一些 僱員也正在領取工資,如果容許這樣做必然出現混亂。
在處理線程同步時,要做的第一件事就是要把修改數據的方法用關鍵字synchronized來修飾。一個方法使用關鍵字sync hronized修飾後,當一個線程A使用這個方法時,其他線程想使用這個方法時就必須等待,直到線程A使用完該方法。
舉例:E50(Example19_9)
六、在同步方法中使用wait()、notify()和notifyAll()方法
當一個線程正在使用一個同步方法時(用synchronized修飾的方法),其他線程就不能使用這個同步方法。對於同步方法, 有時涉及到某些特殊情況,比如當你在一個售票窗口排隊購買電影票時,如果你給售票員的錢不是零錢,而售票員又沒有零錢找給你,那 麼你就必須等待,並允許你後面的人買票,以便售票員獲得零錢找給你。
當一個線程使用的同步方法中用到某個變量,而此變量又需要其他線程修改後才能符合本線程的需要,那麼可以在同步方法中使用wai t()方法,使本線程等待,並允許其他線程使用這個同步方法。其他線程如果在使用這個同步方法時不需要等待,那麼它使用完這個同 步方法的同時,用notifyAll()方法通知所有的由於使用這個同步方法而處於等待的線程結束等待,再次使用這個同步方法。 如果使用notify(),那麼只是通知第一個處於等待的線程結束等待。
舉例:E51(Example19_10)
Java網絡編程
一、使用URL
1.Internet尋址
“IP”代表Internet Protocol(Internet協議)。一個IP地址唯一的標識了Internet上的一臺計算機。沒有IP(Intern et Protocol)地址就不能區分連在Internet上不同的計算機。
2.使用URL定位資源
IP地址唯一標識了Internet上的計算機,而URL則標識了這些計算機的資源。URL(uniform resource locators:統一資源定位符)充當一個指針 ,指向Web上的Web頁、二進制文件以及其他的信息對象。當我們輸入例如
http://www.dlrin.edu.cn/hotlink.html的網址時,實際上就提供了該站點主頁的URL。
因爲Web頁駐留在連接到Internet的某臺計算機上,所以當引用該頁面時就需要確定計算機,故IP地址在URL中扮演了重 要的角色。因此,URL自然包含給定資源的計算機的IP地址,包含資源的計算機就是資源的主機。我們分析一下網址
http://www.dlrin.edu.cn/hotlink.html所包含的信息:
http:服務使用的協議(HTTP)。
dlrin.edu.cn:存儲資源的計算機的域名地址。
hotlink.html:資源。
3.客戶與服務器
Web的客戶/服務器體系結構的含義就是,客戶需要某些類型的信息,而服務器提供客戶所需要的信息。客戶需要連接到服務器上,並 向服務器請求信息;而服務器則向客戶發送信息。兩者協同工作,各得其所。
4.一些基本網絡類
下面是一些由Java的網絡API(應用程序接口)所提供的基本網絡類,它們都包含在java.net包中。其中的URL類提供 了許多構造方法,可以利用它們創建URL。其中最簡單的構造方法只要求提供表示URL資源的字符串:public URL(String s);
下面的例子利用這種構造方法創建一個URL對象url:
try{ url = new URL(“http://www.dlrin.edu.cn”);}
catch(MalformedURLException e){ System.out.println(“Bad URL:”+url);}
由於這個URL構造方法在運行出錯時會產生異常,所以必須在try-catch結構中創建URL對象。但如上面代碼所示,做起來 並不麻煩。
成功創建了URL對象後,就可以練習其他的Java網絡功能了。例如,可以在Applet中鏈向另外的Web頁面,下面的代碼實 現了這個功能:
getAppletContext().showDocument(url);
在小程序中可以放心使用這個方法,因爲getAppletContext()方法是在Applet類中定義的,showDocu ment()實際完成定位到另一個Web頁面的工作,程序中只需要提供URL,其他的工作將由Java自動完成。
舉例:E52(Example21_1)
      E53(Example21_3)
二、套接字
1.套接字(Socket和ServerSocket)
IP地址標識Internet上的計算機,端口號標識正在計算機上運行的進程(程序)。端口號與IP地址的組合得出一個網絡套接 字。端口號被規定爲一個16位的整數(0~65535)。其中,0~1023被預先定義的服務通信佔用(如http佔用端口80 ,ftp佔用端口21等)。除非我們需要訪問這些特定服務,否則,就應該使用1024~65535這些端口中的某一個進行通信, 以免發生端口衝突。
當兩個程序需要通信時,可以通過使用Socket類建立套接字連接。我們可以把套接字連接想像爲一個電話呼叫,當呼叫完成後,談 話的任何一方都可以隨時講話。但是在最初建立呼叫時,必須有一方呼叫,而另一方則監聽鈴聲。這樣,呼叫的一方爲“客戶”,負責監 聽的一方爲“服務器”。
2.客戶建立到服務器的套接字對象(Socket)
客戶端的程序使用Socket類建立與服務器的套接字連接。其構造方法是:
Socket(String host,int port);//參數host是服務器的IP地址,port是一個端口號。
建立時可能發生IOException異常,因此建立與服務器的套接字連接應像如下所示:
try { Socket  mysocket = new  Socket(“http://dlrin.edu.cn”,1880); }
catch ( IOException  e ) { }
當套接字連接mysocket建立後,你可以想像一條通信“線路”已經建立起來。Mysocket可以使用getInputSt ream()方法獲得一個輸入流,然後這個輸入流讀取服務器放入“線路”的信息(但不能讀取自己放入“線路”的信息,就像打電話 時只能聽到對方的聲音一樣)。mysocket還可以使用getOutputStream()方法獲得一個輸出流,然後用這個輸 出流將信息寫入“線路”。
在編寫程序時,把mysocket使用getInputStream()方法獲得的輸入流接到另一個數據流上(和在文件輸入輸出 流所進行的連接,道理是一樣的),然後就可以從這個數據流讀取來自服務器的信息,之所以這樣做是因爲DataInputStre am流有更好的從流中讀取信息的方法。同樣的道理,把mysocket使用getOutputStream()方法得到的輸出流 接到另一個DataOutputStream數據流上,然後向這個數據流寫入信息,發送給服務器端。
3.建立接受客戶套接字的服務器套接字(ServerSocket)
客戶負責建立客戶到服務器的套接字連接,即客戶負責呼叫。因此服務器必須建立一個等待接收客戶套接字的服務器套接字。服務器端的 程序使用ServerSocket類建立接收客戶的套接字的服務器套接字。其構造方法是:
ServerSocket(int port);//port是一個端口號。port必須和客戶呼叫的端口號相同。
建立服務器套接字時可能發生IOException異常,因此應像下面那樣建立服務器套接字:
try {  ServerSocket  server_socket = new ServerSocket(1880);}
catch(IOException e){ }
當服務器的套接字連接server_socket建立後,可以使用accept()方法接收客戶的套接字mysocket。
server_socket.accept();
接收客戶套接字的過程也可能發生IOException異常,因此應像下面那樣建立接受客戶的套接字:
try {  Socket  sc = server_socket.accept(); }
catch(IOException e){ }
收到這個客戶的mysocket後,把它放到一個已聲明的Socket對象sc中,那麼sc就是mysocket(當serve r_socket再收到另外一個客戶的套接字,比如hersocket,可以再把它放到另外一個Socket對象中)。這樣服務 器端的sc可以使用方法getOutputStream()獲得一個輸出流,然後用這個輸出流向“線路”寫入信息,發送給客戶端 。可以使用getInputStream()方法獲得一個輸入流,然後用這個輸入流讀取客戶放入“線路”中的信息。
雙方通信完畢後,應友好地關閉套接字連接:sc.close();
舉例:E54(Example21_4)
4.把套接字連接放在一個線程中
套接字連接中涉及到輸入流和輸出流操作,爲了不影響我們做其他的事情,我們應把套接字連接放在一個單獨的線程中去進行。另外,服 務器收到一個客戶的套接字後,就應該啓動一個專門爲該客戶服務的線程。
舉例:E55(Example21_5)
Java與數據庫的連接(JDBC技術)
JDBC(Java DataBase Connectivity)是Java數據庫連接API。簡單地說,JDBC能完成3件事:
(1)與一個數據庫建立連接;
(2)向數據庫發送SQL語句;
(3)處理數據庫返回的結果。
JDBC在設計上和ODBC很相似。JDBC和數據庫建立連接的一種方式是首先建立起一個JDBC-ODBC橋接器。由於ODB C驅動程序被廣泛的使用,建立這種橋接器後,使得JDBC有能力訪問幾乎所有類型的數據庫。
一、設置數據源
假設有一個用Access設計的數據庫:student.mdb,該庫中有一個表,表的名字是chengjibiao。爲了和這 個數據庫建立連接,首先配置一個ODBC數據源。
假設操作系統爲WindowsXP,打開WindowsXP中的控制面板,選擇“性能和維護”-“管理工具”,雙擊“數據源(O DBC)”,選擇“系統DSN”-“添加”-“Microsoft Access Driver(*.mdb)”,點擊“完成”按鈕進入“ODBC Microsoft Access安裝”窗口,輸入數據源名“redsun”,點擊“選擇”按鈕進入“選擇數據庫”路徑窗口,選擇完數據庫目錄和數據 庫名student.mdb後,確認並一步步退出。(P285)
點擊“高級”按鈕可設置“login name”和“password”。
二、JDBC-ODBC橋接器
1.建立JDBC-ODBC橋接器
現在我們有了一個數據源,這個數據源就是一個數據庫。
爲了連接到這個數據庫,首先要加載JDBC-ODBC bridge驅動程序,即建立一個JDBC-ODBC橋接器:Class.forName(“sun . jdbc . odbc . JdbsOdbcDriver”);
Class是包java.sql中的一個類,該類通過調用它的靜態方法forName()就可以建立JDBC-ODBC橋接器。
建立橋接器時可能發生異常,因此必須捕獲這個異常。所以建立橋接器的標準方法是:
try {  Class.forName(“sun . jdbc . odbc . JdbsOdbcDriver”);}
catch ( ClassNotFoundException e ) { }
2.連接到數據庫
首先使用包java.sql中的Connection類聲明一個對象,再使用類DriverManager調用它的靜態方法ge tConnection()創建這個連接對象:
Connection con = DriverManager.getConnection(“jdbc:odbc:數據源名字”,“數據源的login name”,“數據源的password”);
如果沒有爲數據源設置login name和password,那麼連接形式爲:
Connection con = DriverManager.getConnection(“jdbc:odbc:數據源名字”,“”,“”);
所以爲了能和數據源redsun交換數據,先建立connection對象如下:
Connection con = DriverManager.getConnection(“jdbc:odbc:redsun”,“snow”,“ok”);
建立連接時應捕獲SQLException異常。
try {
Connection con = DriverManager.getConnection(“jdbc:odbc:redsun”,“snow”,“ok”); }
catch(SQLException e){ }
這樣就建立了到數據庫student.mdb的連接。
3.向數據庫發送SQL語句
首先使用Statement聲明一個SQL語句對象,然後通過剛纔創建的連接數據庫的對象con調用createStateme nt()方法創建這個SQL語句對象。
try { Statement sql = con.createStatement();}
catch(SQLException e){ }
4.處理查詢結果
有了SQL對象後,就可以調用相應的方法實現對數據庫的查詢和修改。並將查詢結果存放在一個ResultSet類聲明的對象中, 也就是說SQL語句對數據庫的查詢操作將返回一個ResultSet對象:
ResultSet  rs = sql.executeQuery(“SELECT * FROM  成績表”);
ResultSet對象實際上是一個管式數據集,即它是由統一形式的列組織的數據行組成。ResultSet對象一次只能看到一 個數據行,使用next()方法走到下一數據行。獲得一行數據後,ResultSet對象可以使用位置索引(第一列使用1,第二 列使用2等等)或使用列名稱,以便使用getxxxx()方法獲得字段值。
ResultSet對象的若干方法:
boolean  next();
byte  getByte(int columnIndex);
Date  getDate(int columnIndex);
double  getDouble(int columnIndex);
float  getFloat(int columnIndex);
int  getInt(int columnIndex);
long  getLong(int columnIndex);
String  getString(int columnIndex);
byte  getByte(String columnName);
Date  getDate(String columnName);
double  getDouble(String columnName);
float  getFloat(String columnName);
int  getInt(String columnName);
long  getLong(String columnName);
String  getString(String columnName);
舉例:E56(Example23_2)
Java中的鼠標事件和鍵盤事件
 發生鼠標事件的事件源往往是一個容器,當鼠標進入容器、離開容器,或者在容器中單擊鼠標、拖動鼠標時都發生了鼠標事 件。
一、使用MouseListener接口處理鼠標事件
1.事件源發生的鼠標事件有5種:按下鼠標鍵、釋放鼠標鍵、擊鼠標鍵、鼠標進入和鼠標退出。
鼠標事件的類型是MouseEvent,即當發生鼠標事件時,MouseEvent類自動創建一個事件對象。
MouseEvent類中有下列幾個重要的方法:
getX(),getY():獲取鼠標的座標位置。
getModifiers():獲取鼠標的左或右鍵。
getClickCount():獲取鼠標被點擊的次數。
2.事件源獲得監視器的方法是addMouseListener(監視器)。
3.處理事件源發生的事件的接口是MouseListener。接口中有如下方法:
MousePressed(MouseEvent):負責處理鼠標按下事件。即當在事件源按下鼠標時,監視器發現這個事件後將自 動調用接口中的這個方法對事件作出處理。
MouseReleased(MouseEvent):負責處理鼠標釋放事件。即當在事件源釋放鼠標時,監視器發現這個事件後將 自動調用接口中的這個方法對事件作出處理。
MouseEntered(MouseEvent):負責處理鼠標進入容器事件。即當鼠標進入容器時,監視器發現這個事件後將自 動調用接口中的這個方法對事件作出處理。
MouseExited(MouseEvent):負責處理鼠標離開容器事件。即當鼠標離開容器時,監視器發現這個事件後將自動 調用接口中的這個方法對事件作出處理。
MouseClicked(MouseEvent):負責處理點擊鼠標事件。即當鼠標被擊時,監視器發現這個事件後將自動調用接 口中的這個方法對事件作出處理。
舉例:E57(Example18_1)
二、使用MouseMotionListener接口處理鼠標事件
1.事件源發生的鼠標事件有2種:拖動鼠標和移動鼠標(鼠標鍵不按下)。
鼠標事件的類型是MouseEvent,即當發生這類事件時,MouseEvent類自動創建一個事件對象。
2.事件源獲得監視器的方法是addMouseMotionListener(監視器)。
3.處理事件源發生的事件的接口是MouseMotionListener。接口中有如下方法:
MouseDragged(MouseEvent):負責處理鼠標拖動事件。
MouseMoved(MouseEvent):負責處理鼠標移動事件。
舉例:E58(Example18_6)
三、控制鼠標的指針形狀
當發生鼠標事件時,可以使用setCursor()方法設置鼠標指針形狀,所有的組件都從它們的父類繼承下來了這個方法。下面列 出了Windows平臺上的常見鼠標指針形狀的定義:
HAND_CURSOR     MOVE_CURSOR     WAIT_CURSOR     CROSSHAIR_CURSOR
NE_RESIZE_CURSOR     SE_RESIZE_CURSOR     N_RESIZE_CURSOR     E_RESIZE_CURSOR
舉例:E59(Example18_8)
四、鍵盤事件
當按下、釋放或敲擊鍵盤上一個鍵時就發生了鍵盤事件。當一個組件處於激活狀態時,它就可以成爲發生鍵盤事件的事件源。
事件源使用addKeyListener方法獲得監視器。監視器是一個對象,創建該對象的類必須實現接口keyListener 。接口keyListener中有3個方法:
public void keyPressed(KeyEvent e);
public void keyTyped(KeyEvent e);
public void keyReleased(KeyEvent e);
 當按下鍵盤上某個鍵時,監視器就會發現,然後keyPressed()方法會自動執行,並且KeyEvent類自動 創建一個對象傳遞給方法keyPressed中的參數e。方法keyTyped是keyPressed和keyReleased 方法的組合,當鍵被按下又釋放時,keyTyped()方法被調用。
 KeyEvent類提供了一個方法:public int getKeyCode();用來判斷哪個鍵被按下或釋放。
 舉例:E60(Example18_12)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章