Part1:
Junit根據名稱來識別一個測試方法,所以測試方法的命名要遵從下面的標準:
1. 方法必須聲明爲public
2. 方法的返回值必須爲void
3. 方法的名字必須以小寫test爲前綴
4. 方法不能接受任何參數
命名約定:
Java用稱爲’駝峯模式”的命名方式,可以把多個單詞直接連接起來組成一個名字或者標誌符.除了第一個單詞,標識符中的每一個單詞都以大寫字母開頭.
並且對於類第一個字母爲大寫StudentDirectory,對於方法第一個字母爲小寫firstNameString
不能用數字作爲開頭,避免下滑線’_’,除了類常量和爲了避免因爲衝突而在一個命名前面加一個前綴’_’或者直接加一個其他字母前綴或者是隻有這個命名的首字母
避免縮寫
Java對大小寫是敏感的
在junt裏面存在斷言機制assertEquals(“Joe”,studentName);來對比2個參數是否相等,如果不相等就junt出現紅條
字符串常量的定義
final String firstStudentName = “Jane Doe”;
語句開頭的關鍵字final,表明這個字符串引用是不可修改的.
剛學習的開發循環是:
1. 編寫一個小的測試,來斷言某些功能正確與否
2. 運行測試,如果結果是失敗
3. 編寫代碼,使測試通過
4. 重構測試和代碼.清楚重複的概念,確保代碼富於表現力
Java編譯器允許成員變量的名字和參數的名字相同,甚至和局部變量的名字相同.編譯代碼的時候,Java試着弄明白name代表什麼.編譯器的解決方案就是就近原則,使用最近定義的name就是說是形式參數的name
如果是非必要最好不要把成員變量暴露給其他變量
Part2:
記住:面向對象系統是行爲建模.行爲通過向對象發送消息產生作用—讓對象做某件事情或者從對象獲取數據
Java的int型允許的整形數字範圍是-2147483648到2147483647
Java虛擬機總是先執行某個賦值語句右邊的代碼,Java虛擬機計算出等號右邊表達式的值,然後將結果賦值給左邊
public classAllTesrs {
public static junit.framework.TestSuite suite(){
junit.framework.TestSuitesuite = newjunit.framework.TestSuite();
suite.addTestSuite(StudentText.class);
suite.addTestSuite(CourseSessionTest.class);
return suite;
}
}
一個測試類套件將會用junit測試2個類.
不然只會有一個類得到測試,存在如果這個2個類有關聯的話一個類通過,另外一個類不通過
運用靜態的目的是爲了讓junit能識別
java.util.ArrayList<Student>allStudents = session.getAllStudents();
可以用這種方法來調用JDK的向量
Java的每個類都直接或間接地繼承自java.lang.Object
向量增量的語句是add(變量)
在java中可以用import來把一個包/類包含進你的代碼,如果再次用到這個類就可以直接調用,不需要寫出該類具體的地方
import junit.framework.TestCase;
import java.util.ArrayList;//這裏再最後類的指明處可以用通配符*就是指整個包
在使用的時候就可以直接用
ArrayList<Student> allStudent =session.getAllStudents();
每個類都默認繼承了基礎類,並且每個類只要調用了String就會自動添加這個庫進去
class ClassName extends java.lang.Object
約定所有的包名都是小寫字母
不能用java或者javax作爲包名的開始,因爲sun已經在使用它們
如果你在setUp方法中編寫代碼,JUint將在執行每個測試方法之前先執行setUp方法中的代碼,你可以將公共的測試初始化代碼放在setUp中
所以可以用setUp來測試是否申請成功
private CourseSession session;
public void setUp(){
session = new CourseSession("ENGL","101");
}
在CourseSessionTest類中測試CourseSession類是否申請內存空間成功
注意在聲明的時候不要吧session的聲明放在setUp方法中,這樣會變成一個局部變量
並且在CourseSessionTest中,添加成員變量session,並將setUp方法中新建的CourseSession賦值給該變量.這樣,測試方法testCreate和testEnrollStudents就不再需要初始化代碼,兩個測試方法會得到各自獨立的CourseSession實例.兩個測試方法都是在同一個類裏面的
儘管你可以創建構造函數,並在構造函數中編寫公共的初始化代碼,但這樣做是相當差的實踐.最好是在setUp方法中完成測試初始化
作爲原則,你永遠不要賦值給參數,而且,你應該很少應該爲局部對象的引用重新賦值.
如果可以,最好消除代碼中的重複部分,包括字符串的重複
按照約定,用大寫字母來定義類常量,當所有字母都是大寫,用”駝峯模式”來標記就不大可能,所以標準方法是採用下劃線來’_‘分割單詞
class ChessBoard{
staticfinal int SQUARES_PER_STDE = 8;
}
你還將瞭解,等到代碼與系統中的其他部分糾纏在一起的時候,再修改代碼中的問題,比一開始就去修改,要付出更多的代價,不要等太久!
多行註釋可以內嵌單行註釋,但是多行註釋不能內嵌其他多行註釋
Javadoc註釋用來文檔化類和方法,是告訴程序員如何使用使用這個類
@param 是用來描述參數,@return 用來描述返回值
你可能不需要支持超過雙字節範圍的字符,但是如果你需要,java允許使用int類型來處理字符
Java用’\’’’來代表雙引號
避免使用String b = newString(“abc”);
因爲這種方式創建了兩個String對象
你可以將一個字符串和另一個字符串連接起來,從而生成第三個字符串
assertEquals(“abcd”,”ab”.concat(“cd”));
或者:
assertEquals(“abcdef”,”abc” + “def”);
assertEquals(“abcdef”,”abc” + “de” + “f”);這種 + 的用法被稱爲操作符重載
String不能改變字符串的長度,也不能改變字符串所包含的任何字符,這樣做是爲了字符串的最優化
可以改變的字符串是StringBuilder
在類java.lang.StringBuilder中可以用append增加字符,或者toString來得到String
可以用.NEWLINE方法來代替’\n’因爲在不同的系統中這個的意思有差別
Java中的for用法可以用
for(Student student:students){}來遍歷students容器裏面的所有元素
將集合students中的每一個對象賦值給一個類型爲Student的引用,該引用的名字是student,然後在這個上下穩重執行循環體.
面向對象有一個最基本的設計原則:一個類只做好一件事情.由於只做一件事情,所以改變類應該只有一個動機.這就是單職責原則
如果某個類沒有指定訪問修飾符,那麼該類擁有包訪問級別,這也是默認的訪問級別,意味着,同一個包中的其他類可以引用這個類,但是,不同的包中的類不能訪問這個類
可以向測試套件發送addTest消息,這樣就可以直接測試那個套件
suit.addTest(sis.report.AllTests.suite());
如果一個.java中定義了兩個類,則編譯後將產生兩個字節碼文件.class,.在這種情況下,同一Java源文件中最多隻能定義一個public類,如果定義了public類,則要求源程序的文件名必須與public類的名稱相同
可以通過用Apple類來對代碼嵌入到HTML裏
import java.awt.*;
import java.applet.Applet;
public classJavaApplet extends Applet{
public void paint(Graphics g){
g.drawString(JavaApplet!,40, 80);
g.setColor(Color.red);
g.drawLine(30,40, 130, 40);
g.drawOval(30,40, 100, 100);
}
}
然後在編寫HTML的時候可以用
<HTML>
<BODY>
<APPLET CODE = “JavaApplet.class” HEIGHT= 150 WIDTH = 150>
</APPLET>
</BODY>
</HTML>
那麼就會在瀏覽器上現實出這段代碼編譯出來的圖畫
也可以用JDK中提供的AppletViewer.exe來運行查看結果
在命令行方式下,輸出字符串是通過換行定位,在圖形方式下,繪製字符串通過座標定位
標識符不能出現’#’’-‘和數字開頭.
Java所有的關鍵字均爲小寫字母表示
goto和const任然爲java的關鍵字,雖然沒有用
java的布爾類型是boolean
可以用Byte.MIN_VALUE,Byte.MAX_VALUE來獲得byte的取值範圍,也可以用到double,char,float等
系統自動轉換的順序是
byte->short->char->int->long->float->double
在以上的順序上不需要強制轉換,系統會自動進行轉換
強制轉換格式爲
變量 = (數據類型)表達式
int li = (int)4.25;
若輸入一個常實數都將默認爲雙精度型例如float f = 3.14;編譯會報錯,要float f =3.14f;纔可以
C++上的運算符在java上基本適用
~op結果是op按比特位求反
op1>>op2將op1右移op2個位(帶符號)
op1>>>op2將op1右移op2個位(不帶符號)
op1^op2兩個值是不同值
instanceof用來決定第一個運算對象是否爲第二個運算對象的一個實例
String x = “hello world!”;
if(x instanceof String)
Syste.out.println(“sis a instance of String”);
System.out.read();是從鍵盤讀一個”字節”具體要轉換成什麼要強制轉換,要包含java.io.*;
可以用BufferReaderin = new BufferedReader(new InputStreamReader(System.in));
String s = “”;
s = in.readLine();//來讀取一行字符
可以用
String x = “123”;
int m = Interger.parseInt(x);
x = “123.41”;
double n = Double.parseDouble(x);
這種方法獲得整形和雙精度型
Math.pow(x,n)用來計算x的n次方
Java可以定義標籤用break 標籤可以調到這個標籤上,可以用於跳到哪個for上
如果是對類,那麼對形參類的修改也會對實參修改,基本類型就不會
可以用packagetest;放在類頭,然後創建一個test子目錄來建立這個包
如果存在用import中的類在2個引用中都出現的時候就需要指定具體在哪個包的路徑
子類在自己定義的構造方法中如果沒有用super明確調用父類的構造方法,則在創建對象時,將自動調先執行父類的無參構造方法,然後再執行自己定義的構造方法
public classStudent extends Person{
Stringno;
public Student(Stringname1,String address1,int age1,String no1){
super(name1,adress1,age1);
no=no1;
}
}
用protected修飾的成員可以被3中類所引用
1. 該類本身
2. 與該類在同一個包中的其他類
3. 在其他包中的該類的子類
在繼承中使用final修飾符修飾的方法不能被覆蓋
可以通過super.來調用父類被覆蓋的方法
用abstract關鍵字來指明這個類是抽象類,一樣不能實例化
可以用implements來實現接口interface
abstract public class Rectangle implementsShape{…}//shape是一個接口
有內嵌類的類生成的文件名字是outerOne$innerOne.class
內嵌類可以訪問外層類的成員,也可以外層類訪問內嵌類的成員,但是要同對象來訪問(非靜態),靜態不用
外層類中this要加上外層類的名字outerOne.this.
編寫Applet需要繼承java.applet.Applet類
init()方法用來對Applet對象初始化
start()方法用來啓動Applet主線程運行,在init()方法運行結束後運行,以後每次Applet激活都會調用它,默認內容爲空
paint()方法用來繪製文字,圖形等,利用Graphics參數來發送消息
stop()方法用來暫停Applet主線程
destroy()方法用來釋放資源,如果是調用了特殊資源就要調用方法
repaint(int x, int y, int width, int height)指定座標重繪
可以調整字體的屬性
Font myFont = new Font(“TimesRoman”,Font.BOLD + Font.ITALIC, 28);
g.setFont(myFont);
來設置,第一個參數是字體名,第二個參數是風格,第三個參數是字號
字體風格有Font.PLAIN,Font.ITALIC,Font.BOLD分別代表普通,斜體和粗體
也可以使用FontMetrics類來獲得當前字體的屬性,首先用getFontMetrics(Font)方法來獲得一個FontMetrics對象引用,然後:
intstringWidth(String str);
intgetHeight();
intcharwidth(char ch);
在所有的圖形部件的父類Component中有如下方法可以獲得Applet的寬度和高度
getHeight();getWidth();
Math.floor方法得到的是一個不大於參數的最大整數,返回的是雙精度值
Math.floor(Math.random()* 256);
可以用<param name = “vs” value = “可變大小的字符串”>
<paramname = “size” value = 24>;
來在HTML中獲得2個參數
getImage(getDocumentVase(),”images\\img00”+ (i+1) + “.gif”);獲得圖片,循環獲取
play(getDocmentBase(),“passport.mid”);獲得播放文件
AudioClip接口:
publicvoid play();開始播放
publicvoid loop();循環播放當前聲音文件
publicvoid stop();停止播放當前的聲音文件
可以用Applet類的getAudioClip(URL,String)來獲得當前AudioClip類型的對象
AWT工具集是抽象的,因爲Java設計成跨平臺的,因爲每個平臺的外觀不同
intx = Integer.parseInt(s, 2); s代表的二進制串轉換成十進制
網格
public GridLayout(int rows,int cols,int hgap,int vgap)
rows - 行數,0
表示每列可有任意行。
cols - 列數,0
表示每行可有任意列。
hgap - 水平間距。
vgap - 垂直間距。
importjava.awt.*;
importjava.awt.event.*;
publicclass converToDec extends Frame implements ActionListener{
Label dec;
TextField input;
publicconverToDec(){
super("binary to decimal");//用於定義標題,實爲父類的構造函數
dec = new Label("...結果...");
input = new TextField(15);
Button convert = new Button("轉換");
setLayout(new FlowLayout());//指定按流式佈局排列部件
add(input);
add(convert);
add(dec);
convert.addActionListener(this);
}
publicvoid actionPerformed(ActionEvent e){
String s = input.getText();
int x = Integer.parseInt(s, 2);
dec.setText("result =" + x);
}
publicstatic void main(String args[]){
Frame x= new converToDec();
x.setSize(400, 100);
x.setVisible(true);
}
}
運用繼承Frame來實現,也可以通過創建Frame對象來實現
importjava.awt.*;
importjava.awt.event.*;
publicclass converToDec extends Panel implements ActionListener{
Label dec;
TextField input;
publicconverToDec(){
//super("binaryto decimal");
dec = new Label("...結果...");
input = new TextField(15);
Button convert = new Button("轉換");
setLayout(new FlowLayout());
add(input);
add(convert);
add(dec);
convert.addActionListener(this);
}
publicvoid actionPerformed(ActionEvent e){
String s = input.getText();
int x = Integer.parseInt(s, 2);
dec.setText("result =" + x);
}
publicstatic void main(String args[]){
Frame x= newFrame("binary to decimal");
x.add(new converToDec());
x.setSize(400, 100);
x.setVisible(true);
}
面板(Panel)是一種常用的GUI容器,在面板上可以不知各種GUI部件,包括將一塊麪板放在另一塊麪板中,以實現某些複雜的嵌套佈局
事件處理包括如下3個對象
1. 事件源:發生時間的GUI部件
2. 事件:用戶對事件源進行操作觸發事件
3. 事件監聽者:負責對時間的處理
給事件源對象註冊監聽者
事件監聽者是在事件發生時要對事件進行處理的對象,AWT定義了各種類型的事件,每一種事件有相應的事件監聽者接口,在接口中描述了處理相應事件應實現的基本行爲..若事件類名爲XxxEvent,則事件監聽接口的命名爲XxxListener,給部件註冊監聽者的方法爲addXxxListener(XxxListenera).例如,按鈕動作事件ActionEvent的監聽者接口爲ActionListener,給按鈕註冊監聽者的方法爲addActionListener(ActionListenera).
Java的事件處理機制稱爲委託事件處理,事件源發生事件時由監聽者處理.監聽者中定義事件處理方法,事件源不需要實現任何接口,但其內部有個列表記錄該事件源註冊了哪些監聽者,從而保證發生事件時能去調用監聽者的方法
以按鈕事件源爲例,在發生事件時,事件源將給其註冊的所有監聽者發送消息,實際上就是調用監聽者對象的actionPerformed()方法,從而完成事件的處理
一個事件源對象可以註冊多個監聽者,一個監聽者也可以監視多個事件源.
import java.awt.*;
import java.awt.event.*;
public classTwoButton extends Panel implements ActionListener{
Buttonb1,b2;
Paneldraw;
public TwoButton(Panel draw){//得到繪圖面板要引用繪圖面板
this.draw = draw;
b1 = new Button("circle");
b2 = new Button("rectangle");
add(b1);
add(b2);
b1.addActionListener(this);
b2.addActionListener(this);
}
public voidactionPerformed(ActionEvent e){
Graphicsg = draw.getGraphics();//得到繪圖面板的迴避對象
g.setColor(draw.getBackground());
g.fillRect(0,0,draw.getSize().width, draw.getSize().height);
g.setColor(Color.blue);
Stringlabel = e.getActionCommand();//取得事件按鈕的標籤
if(label.equals("circle"))
g.drawOval(20,20, 50, 50);
else
g.drawRect(20,20, 40, 60);
}
public static void main(String args[]){
Framef = newFrame("two Button event Test");
Paneldraw = newPanel();//創建繪圖面板
TwoButtontwo = newTwoButton(draw);//創建控制面板
f.setLayout(new BorderLayout());//採用邊界佈局
f.add("North",two);//控制面板放在下方
f.add("Center",draw);//繪圖面板放在中央
f.setSize(300,300);
f.setVisible(true);
}
}
不少事件的監聽者接口中定義了多個方法,而程序員往往只關心其中的一兩個方法,爲了符合接口的實現要求,卻必須將其他方法寫出來併爲其提供空的方法體.爲此,Java中爲那些具有多個方法的監聽者接口提供了時間適配器類,這個類通常命名爲XxxAdapter,在該類中以空方法體實現了相應接口的所有方法,程序員設計可通過繼承適配器類來編寫監聽者類.在類中只需給出關心的方法,從而減輕了工作量.
dispose()爲關閉窗體的方法
java.awt包中共定義了5種佈局管理器,與之對應有5種佈局策略:流式佈局(FlowLayout),邊緣或方位佈局(BorderLayout),網格佈局(GridLayout),卡片式佈局(CardLayout),網格快佈局(GridBagLayout),通過setLayout()方法可以設置容器的佈局方式
如果不進行設定,則各種容器採用默認的佈局管理器,窗體容器默認採用BorderLayout,而面板容器默認採用FlowLayout
FlowLayout佈局方式將組件按照加入的先後順序從左到右排放,放不下再換至下一行,同時按照參數要求安排部件間的縱橫間隔和對齊方式
可以在Frame窗體中現實Applet面板
最用FlowLayout佈局的一個重要特點是佈局管理器不會改變控件的大小
BordLayout黨容器僅有有個部件時,如果部件加入在北方,則它僅佔用北區,其他地方爲空白,但如果是加入到中央,則部件將佔滿整個容器
import java.applet.*;
import java.awt.*;
public classBorderLayoutExample extends Applet{
Stringborders[]= {"North","East","South","West","Center"};
public void init(){
this.setLayout(new BorderLayout(10, 10));
for(int i = 0;i < 5; i ++){
this.add(borders[i], new Button(borders[i]));//通過這個函數來加入,不同的風格的參數不同
}
}
public static void main(String args[]){
Framex = newFrame("FlowLayout");//爲了能在應用程序上現實出來加上主函數
BorderLayoutExampley = newBorderLayoutExample();
x.add(y);
x.setSize(200,100);
x.setVisible(true);
}
}
BorderLayout的特點是組件尺寸被佈局管理器強行控制,即與其所在區域的尺寸相同.如果某個區域無部件,則其他局域將按縮放規則自動佔用其位置
GridLayout佈局的特點是組件整齊排列,行列位置關係固定,如果調整容器的大小,組件的大小也將發生變化
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public classCardLayoutExample extends Applet{
public void init(){
final CardLayout cardlayout = new CardLayout(10, 10);
this.setLayout(cardlayout);
ActionListenerlistener = newActionListener(){//創建監聽者對象
public voidactionPerformed(ActionEvent e){//事件處理
cardlayout.next(CardLayoutExample.this);
}
};
for(int i = 1; i <= 9;i ++){
Buttonb = newButton("Button #" + i);
b.addActionListener(listener);//給按鈕註冊監聽者
this.add("Button"+ i,b);
}
}
public static void main(String args[]){
Framex = newFrame("FlowLayout");
CardLayoutExampley = newCardLayoutExample();
x.add(y);
x.setSize(200,100);
x.setVisible(true);
}
}
基本控制部件被安放在容器中的某個位置,用來完成一種具體的與用戶交叉的功能.使用基本控制部件的步驟爲:
1. 創建某種基本控制部件類的對象,指定該對象的屬性,如外觀,大小等;
2. 將該對象加入到某個容器的合適位置
3. 爲該對象註冊事件監聽者
可以通過setEchoChar(char)來設置文本框的回顯字符
TextFieldpass = new TextField(8);
Pass.setEchoChar(‘*’);
把CheckboxGroup加入容器時必須將每個Checkbox對象逐一加入容器,不能使用CheckboxGroup對象一次加入
與單選按鈕不同的是,下拉列表是作爲一個整體加入到容器,各個列表元素不是獨立的操作對象
列表產生的可以產生兩種事件
1. ItemEvent類選擇事件,當單機某選項時觸發
2. ActionEvent類動作事件,當雙擊某選項時觸發
值得注意的是,雙擊事件不能覆蓋單擊事件,當用戶雙擊一個選項時,首相產生一個雙擊,然後產生一個單擊
低級語義事件會比高級語義事件先執行
哪個監聽就要有方法實行,要實現某監聽接口
吧事件源註冊給能處理該類型事件的監聽者
異常處理:
1. try語句塊用來啓動java的異常處理機制.一個try可以引導多個catch塊
2. 異常發生後,try塊中的剩餘語句將不再執行.
3. 異常對象是依靠以catch語句爲標誌的異常處理語句塊來捕捉和處理的.catch塊中的代碼要執行的條件是,首先在try塊中發生了異常,其次異常的類型與catch塊要捕捉的一致,在此情況下,運行系統會將異常對象傳遞給catch中的參變量,在catch塊中可以通過該對象獲取異常的具體信息
4. 在該結構中,可以無finally部分,但如果存在,則無論異常發生與否,finally部分的語句均要執行,即使是try或catch塊中嵌套退出方法的語句return,也不能住址finally代碼塊的執行,也就是先執行finally塊,然後再返回.除非遇到System.exit(0)時將停止程序運行.
所有的系統定義的運行異常都可以由系統在運行系統過程中自動拋出.而用戶設計的異常,則要在程序中通過throw語句拋出,異常本質上是對象,因此throw關鍵詞後面跟的是new運算符來創建一個異常對象
publicclass TestException{
public static void main(Sring a[]){
try{
throw new MyException(“一個測試異常”);
}
catch(MyExceptione){
System.out.Println(e);
}
}
}
Throw語句和throws字句的差異性,一個是拋出異常,另一個是聲明方法產生某個異常(throws)
在編寫類繼承代碼時要主義,子類在覆蓋父類帶throws字句的方法時,子類的方法聲明中的throws字句拋出的異常不能超出父類方法的異常範圍,因此,throws字句可以限制子類的行爲.換句話說,子類方法拋出的異常可以是父類方法中拋出異常的子類,子類方法也可以不拋出異常,但不能出現父類對應方法的throws字句中沒有的異常類型
用戶自定義異常必須繼承Exception類,在方法中課通過throw拋出異常,對未處理異常課通過方法頭的throws字句聲明該方法將產生異常.在其他方法中調用會產生異常的方法必須對異常進行處理或在自己的方法頭中聲明拋出異常
數據的讀取通常是按照順序逐個字節進行訪問,在某些特殊情況下,要重複處理某個字節可以通過mark()加標記,以後用reset()返回該標記處再處理
要從鍵盤得到整數只能先讀取字符串,再利用其他方法,如:Integer.parseInt(String)將數字字符串轉化爲整數.
FileOutStreamfile = new FileOutStream(“x.dat”);
DataOutStreamout = new DataOutputStream(file);
首先創建一個FileOutStream文件輸出流,如果對應名稱的文件不存在,系統會自動新建一個該名字的文件,.而後,針對該文件,創建了一個DataOutputStream流,這樣可以利用該流給文件寫入各種基本類型的數據.
publicvoid write(int c);往一個文件寫入一個字符,它是將證書的低16位對應的數據寫入文件,高16位忽略.
當輸入源的數據不符合對象規範或無數據時將產生IOException異常
調用對象輸入流的readObiect()方法必須捕捉ClassNotFound異常
爲了實現用戶自定義對象的串行化,相應的類必須實現Serializable接口,否則,不能以對象形式正確寫入文件
創建新線程必須編寫一個線程類,用java編寫多線程代碼有兩種方式:第一種方式是直接繼承java的線程類Thread;第二種方式是實現Runnable接口.無論採用哪種方式均需要在程序中編寫run()方法,線程在運行時要完成的任務在該方法中實現
下面幾種情況下,當前線程會放棄CPU:
1. 當前時間片用完
2. 線程在執行時調用了yield()或sleep()方法主動放棄
3. 進行i/o訪問,等待用戶輸入,導致線程阻塞,或者爲等候一個條件變量,線程調用wait()方法
4. 有高優先級的線程參與調度
注意在程序中不要直接調用run()方法,而是調用線程對象的start()方法啓動線程,讓其進入可調度狀態,線程獲得調度時自動執行run()方法
import java.applet.*;
import java.awt.*;
class countbutton extends Button implements Runnable{
int count = 0;
public countbutton(String s){
super(s);
}
public void run(){
while(count < 10000){
try{
this.setLabel("" + count ++);
Thread.sleep((int)(10000 * Math.random()));
}
catch(Exception e){}
}
}
}
public classCountApplet extends Applet{
public void init(){
setLayout(null);
countbuttont1 = newcountbutton("first");
t1.setBounds(30,10, 80, 40);
add(t1);
countbuttont2 = newcountbutton("second");
t2.setBounds(130,10, 80, 40);
add(t2);
(new Thread(t1)).start();//創建線程,將計數按鈕傳遞給線程
(new Thread(t2)).start();
}
}
運行程序將發現兩個按鈕的標籤上現實的數字不斷增加,這裏的按鈕由於實現了Runnable接口,具備線程運行的方法要求,將該”按鈕”對象作爲Thread的參數可以創建線程,線程運行時將執行”按鈕”對象的run方法.另外,該程序沒有采用佈局管理器,而是通過部件的setBounds方法來規定位置,寬,高
調用yield()的效果等於調度程序認爲該線程已經執行了足夠的時間從而轉到另一個線程
通過執行suspend()方法可以讓線程無限等待(Suspending),直到其他線程向這個線程發送resume()消息讓其恢復運行.就是讓線程阻塞,並且不會恢復
線程在進行輸入/輸出時將等待外界提供數據,這種行爲稱爲阻塞(不佔用CPU時間)
設置爲哪種線程的方法是setDaemon(Boolean on),該方法必須在線程啓動前執行
只有程序存在用戶線程時,程序才能保持運行.如果所有的用戶線程均終止了執行,則所有的看守線程也將結束運行
在main方法中創建的線程默認爲用戶線程
執行main方法的線程是用戶級線程
如果希望main方法結束時,終止整個程序的運行,則可以將所有線程指定爲看守線程,這樣在main結束的時候就不存在用戶線程了
多個線程共享的數據稱爲臨界資源,
可以採用synchronized給調用方法的對象加鎖,保證一個方法處理的對象資源不會因其他方法的執行而改變,這就不會出現在調用這個資源的時候被其他代碼運用這個資源,要等這個代碼運行完其他代碼才能用這個資源,所以叫做給這個資源加鎖
Synchronized關鍵字的使用方法有兩種:
1. 用在對象面前,限制一段代碼的執行,表示執行該段代碼必須取得對象鎖
2. 在方法前面,表示該方法爲同步方法,執行該方法必須取得對象鎖
wait()方法使得線程進入阻塞狀態,執行notify()方法時將釋放相應對象佔用的鎖,從而可使因對象資源鎖而處於等待的線程得到運行的機會.
wait()方法和notify()方法在概念上有如下特徵:
1. 這對方法必須在synchronized方法或塊中調用,只有在同步代碼段中才存在資源鎖定
2. 這對方法直接隸屬於Object類,而不是Thread類.也就是說,所有對象都擁有這一對方法
在java.net包中提供了鄧黻的網絡功能,例如,用InetAddress類表示IP地址,用URL類封裝對網絡資源的訪問,用ServerSocket和Socket類實現面向連接的網絡通信,用DatagramPacket和DatagramSocket實現數據報的收發
一個簡單的連接程序
服務器程序:
import java.net.*;
import java.io.*;
public classSimpleServer {
public static void main(String args[]){
ServerSockets = null;
try{
s= newServerSocket(5432);//規定服務端口
}catch(IOException e){}
while(true){
try{
Sockets1 = s.accept();//等待客戶連接
OutputStreams1out = s1.getOutputStream();//取得Socket的輸出流
DataOutputStreamdos = newDataOutputStream(s1out);
dos.writeUTF("Hello World!");
System.out.println("a client is conneted...");
s1.close();
}catch(IOException e){}
}
}
}
客戶程序:
import java.net.*;
import java.io.*;
public classSimpleClient {
public static void main(String args[])throws IOException{
Sockets = newSocket("localhost",5432);//申請與服務器的5432端口連接
InputStreamsIn = s.getInputStream();//取得Socket的輸入流
DataInputStreamdis = newDataInputStream(sIn);
Stringmessage = newString(dis.readUTF());//讀取服務器發送的數據
System.out.println(message);
s.close();
}
}