使用面向對象的思路介紹Java的基礎知識,從對象的基本概念、變量、方法,到函數庫,集成與多態,靜態,再到GUI,序列化,網絡,數據結構,最後介紹發佈和遠程調用。html
本書最大的啓發是創建面向對象的基本思想,萬物皆在對象中,究竟是如何組成和實現的。java
最經常使用的java數據庫
public class ClassName { public static void main(String[] args){ System.out.println("Hello World!"); } }
(int)(Math.random()*length)
來出現隨機數;api
public static final double PI=3.1415
public表示可供各方讀取,static表示不用建立實例便可使用,final表示不變;靜態final變量默認取名大寫,且必須初始化。java.util.Calendar對象來操做日期數組
Calendar cal = Calendar.getInstance(); cal.set(2017,1,6,15,40); cal.getTimeInMillis(); cal.HOUR_OF_DAY cal.add(cal.DATE, 30);//月份滾動 cal.roll(cal.DATE, 30);//月份不動 cal.set(cal.DATE, 1); //重要的方法 add(int field, int amount) get(int field) getInstance() getTimeInMillis() roll(int field, int amount) set(int field, int amount) set(year,month,day,hour,minute) setTimeInMillis(long millis) //關鍵字段 DATE / DAY_OF_MONTH HOUR / HOUR_OF_DAY MILLISECOND MINUTE MONTH YEAR ZONE_OFFSET
import static java.lang.System.out;靜態的import能夠到方法,而後直接調用out便可,不建議使用;瀏覽器
會拋出異常的方法必需要聲明它有可能會這麼作。方法能夠抓住其餘異常,異常總會丟回給調用方;安全
public void takeRisk() throws BadException{ if (abandonAllHope){ throw new BadException(); } } public void crossFingers(){ try{ anObject.takeRisk(); }catch (BadException ex){ System.out.println("Aaargh"); ex.printStackTrace(); } }
throws Exception1, Exception2
;catch也能夠用相似switch語句同樣來分別處理,可是要從小到大;duck異常表示,當調用有異常的方法,也聲明會拋出異常時,能夠不把此方法的調用放在try/catch塊中,可是不推薦這麼作。服務器
監聽和事件源之間的溝統統過程序代碼調用button.addActionListener(this)
來向按鈕註冊。按鈕會在事件發生時,調用註冊該接口的方法actionPerformed(theEvent)
;網絡
import javax.swing.*; import java.awt.event.*; public class SimpleGui1B implements ActionListener{ JButton button; public static void main(String[] args){ SimpleGui1B gui = new SimpleGui1B(); gui.go(); } public void go(){ JFrame frame = new JFrame(); button = new JButton("click me"); button.addAcitonListener(this); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(button); frame.setSize(300,300); frame.setVisible(true); } public void actionPerformed(ActionEvent event){ button.setText("I've been clicked!"); } }
當有多個widget須要監聽事件時,用內部類來解決;數據結構
public void go(){ //... labelButton.addActionListener(new LaberlListener()); colorButton.addActionListener(new ColorListener()); label = new JLabel("I'm a label") //... } class LaberListener implements ActionListener { public void actionPerformed(ActionEvent event){ labnel.setText("Ouch!") } }
每一個背景組件均可以有自定義規則的佈局管理器。BorderLayout表示五個區域,是frame默認的,FlowLayout表示從左至右,有必要時換行,是panel默認的;BoxLayout以垂直排列;
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.add(button); frame.getContentPane().add(BorderLayout.North, panel);
JTextField文本框組件,JTextArea可滾動的文本框組件,JCheckBox組件,JList組件均爲經常使用組件。
序列化寫入的步驟:建立FileOutputStream對應一個文件xxx.ser,有FileStream建立ObjectOutputStream,由ObjectOutputStream寫入object,關閉ObjectOutputStream。其中須要注意,可以寫入ObjectOutputStream的object必須implements Serializable,可是不須要實現任何方法。
FileOutputStream fileStream = new FileOutputStream("MyGame.ser"); ObjectOutputStream os = new ObjectOutputStream(fileStream); os.writeObject(characterOne); os.close();
transient String currentID;
解序列化步驟,建立FileInputStream讀取一個文件,建立ObjectInputStream,讀取對象,轉換對象類型,關閉。
FileInputStream fileStream = new FileInputStream("MyGame.ser"); ObjectInputStream os = new ObjectInputStream(fileStream); Object one = os.readObject(); GameCharacter elf = (GameCharacter) one; os.close()
讀寫文本文件。注意可使用緩衝區的方法來減小磁盤IO。使用writer.flush()強制緩衝區內容寫入磁盤。
import java.io.*; class WriteAFile{ public static void main(String[] args){ try { FileWriter writer = new FileWriter("Foo.txt"); writer.write("hello, foo!"); //BufferedWriter bWriter = new BufferedWriter(writer); //bWriter.flush(); writer.close(); File myFile = new File("Foo.txt"); FileReader fileReader = new FileReader(myFile); BufferedReader reader = new BufferedReader(fileReader); String line = null; while((line = reader.readLine()) != null){ System.out.println(line); } reader.close(); } catch(IOException ex){ ex.printStackTrace(); } } }
java.io.File類的操做
//建立出File對象 File f = new File("MyCode.txt"); //建目錄 File dir = new File("Chapter_8"); dir.mkdir() //列出目錄內容 if (dir.isDirectory()){ String[] dirContents = dit.list(); } //取得絕對路徑 dit.getAbsolutePath(); //刪除文件 boolean isDeleted = f.delete()
每一個對象被序列化的同時,都會帶上一個類的版本的識別ID,即serialVersionUID。所以要注意版本。
網絡接收消息的步驟:創建socket鏈接,輸入到底層的InputStreamReader上,轉換到緩衝區字符BufferedReader,讀取數據;
Socket chatSocket = new Socket("127.0.0.1", 5000); InputStreamReader stream = new InputStreamReader(chatSocket.getInputStream()); BufferedReader reader = new BufferedReader(stream); String message = reader.readline(); reader.close();
寫消息的流程是:創建socket,getOutputSream並創建PrintWriter,寫入數據;
Socket chatSocket = new Socket("127.0.0.1", 5000); PrintWriter writer = new PringWriter(chatSocket.getOutputStream()); writer.println("haha"); writer.close();
服務器端創建服務的流程爲:創建ServerSocket,等待客戶端鏈接,客戶鏈接後,調用accept方法創建新的socket。
ServerSocket serverSock = new ServerSocket(5000); while(true){ Socket sock = serverSock.accept(); PrintWriter writer = new PrintWriter(sock.getOutputStream()); writer.println("haha"); writer.close(); }
Runnable是一個接口,它只有一個方法public void run()。它就是線程要執行的工做。
public class MyRunnable implements Runnable { public void run(){ go(); } public void go(){ System.out.println("top o' the stack"); } } class ThreadTestDrive{ public static void main(String[] args){ Runnable threadJob = new MyRunnable(); Thread myThread = new Thread(threadJob); myThread.start(); System.out.println("back in main"); } }
線程會產生併發性問題(concurrency),併發性問題會引起競爭狀態(race condition),競爭狀態會引起數據損毀。舉個例子,兩個線程共用一個餘額,每次用錢時,先檢查餘額,再扣錢。這樣會因爲競爭緣由出現負數。因此須要一把鎖,來保證一個方法一次只能被一個線程調用,即用synchronized關鍵字。
private synchronized void makeWithDrawa(int amount){ //... }
同步化能夠只修飾幾行,這樣能夠減少原子操做的範圍,提升效率。
private void makeWithDrawa(int amount){ //... synchronized(this){ //... } }
靜態的方法是運行在類上的,當要對靜態的方法作同步化是,會使用類自己的鎖。
泛型有三件事是重要的:
new ArrayList<Song>(); //建立實例 ArrayList<Song> songList = new ArrayList<song>(); //聲明指定泛型類型的變量 void foo(ArrayList<Song> list); //聲明或調用指定泛型的方法
在說明文件中,通常用E表示指定類型;
public class ArrayList<E> extends AbstractList<E> implements List<E> ...{ public boolean add(E o) }
運用泛型的方法可使用未定義在類聲明的類型參數。
public <T extends Animal> void takeThing(ArrayList<T> list) //與後續的萬用字符相同 public void takeThing(ArrayList<? extends Animal>) //與下面不同,下面的只能使用Animal,不能使用其子類 public void takeThing(ArrayList<Animal> list)
一樣若是要使用HashSet去除重複,針對自定義類,要覆蓋equals方法和hashCode方法。它的比較過程是先比較hashCode(),若是相同,再比較equals。
class Song implements Comparable<Song>{ ... public boolean equals(Object aSong){ Song s = (Song)aSong; return getTitle().equals(s.getTitle()); } public int hashCode(){ return title.hashCode(); } }
HashMap適合用KV場景存儲數據
HashMap<String, Integer> scores = new HashMap<String, Integer>(); scores.put("Bert", 43); System.out.println(scores.get("Bert"));
泛型參數和數組參數的區別
public void takeAnimals1(ArrayList<Animal> animals) public void takeAnimals2(Animal[] animals) //takeAnimals1(new ArrayList<Dog> dogs)會出錯,編譯錯誤 //takeAnimals2(new Dog[] dogs)不會出錯 //前者能夠防止在函數中進行Dog的特有相關操做,後者在執行期若是運行相關操做,會拋出異常
爲了解決上述前者的問題,可使用萬用字符
public void takeAnimals3(ArrayList<? extends Animal> animals) //爲了防止此時,將ArrayList<Dog>中加入Cat,當用萬用字符時,不能對隊列作加入操做
可使用-d class_path
來將源代碼與類文件相分離,實現對源碼的保護;
javac -d ../classes *.java
jar相似tar命令,它有本身的規則。首先要肯定全部的類文件都在classes目錄下,其次要有manifest.txt文件來描述哪一個類帶有main()方法,最後執行命令打jar包
cat manifest.txt Main-Class:MyApp cd MiniProject/classes jar -cvmf manifest.txt app1.jar *.class
java -jar app1.jar
。而爲了防止包命名衝突,通常反向使用domain做爲包名稱。
com.headfirstbooks.Book com.headfirstjava.projects.Chart
package com.headfirstjava;
。而後要設定對應的目錄結構。Main-Class:com.headfirstjava.PackageExcise
。在classes目錄下執行jar語句打包,這裏只要指定com路徑就行。
jar -cvmf manifest.txt packEx.jar com
jar -xf packEx.jar
解壓後會發現有META-INF
目錄,其下有MANIFEST.MF
文件,即爲寫入的對應文件。製做可執行jar程序;編寫jnlp文件;二者均放入Web服務器;Web服務器設定新類型application/x-java-jnlp-file
;設定網頁連接到jnlp文件<a href="MyApp.jnlp">Launch My App</a>
rmic MyRemoteImpl
),啓動RMI registry(rmiregistry
),啓動遠程服務(Naming.rebind("Remote Hello", serviceMyRemote)
)。(MyRemote)Naming.lookup("rmi://127.0.0.1/Remote Hello")
),RMIregistry返回stub對象,客戶端調用stub上的方法;Jini也使用RMI,但具備自適應探索(接收服務註冊和客戶端調用查詢)和自恢復網絡(用心跳檢查服務)的功能;
斷言能夠用來測試,它比println的好處是沒有特別設定的話,它會自動被JVM忽略,也可專門打開斷言調試程序。
assert (height > 0) : "height = " + height + " weight = " + weight; //冒號後面的語句能夠是任何返回非null值得語句,但必定要注意不要在這裏改變對象的狀態 //斷言的編譯和普通編譯沒差異,執行時有差別。 javac TestDriveGame.java java -ea TestDriveGame
new Foo().go()
是一個調用go方法,但又不須要維持對Foo引用的方式;匿名內部類。
//button.addActionListener(quitListener); //一般是傳遞一個內部類的實例 //雖然ActionListener是個接口,並且咱們不能聲明一個接口的實例,但匿名內部類是個例外 button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev){ System.exit(0); } });
new int [4][2]
實際上是建立一個包含四個元素的數組,每一個元素是一個長度爲2的數組。public enum Members {JERRY, BOBBY, PHIL};
能夠在enum中加入構造函數,方法、變量和特定常量的內容;
暫無