《Java編程思想》閱讀筆記二

Java編程思想

這是一個經過對《Java編程思想》(Think in java)進行閱讀同時對java內容查漏補缺的系列。一些基礎的知識不會被羅列出來,這裏只會列出一些程序員常常會忽略或者混淆的知識點。html

所列知識點所有都是針對本身我的而言,同時也歡迎你們進行補充。java


第九章(接口)

任何抽象性都應該是應真正的需求而產生的。程序員

訪問權限

p172
interface若是不加public關鍵字,則只具備包訪問權限。算法

重名

p181
能夠經過extends來擴展接口,但在實現多重繼承時要注意不能實現簽名或返回類型不一樣的接口方法,除非其傳入參數不同。最好避免使用同一個方法名稱。編程

interface M{
    void menace();
    void kill();
}

interface Danger{
    void menace(int s);
    void kill();
}

interface Vampire extends Danger,M{

}

public class Monster implements Vampire{
    public static void main(String[] args) {
        System.out.println("Hello,every one,I'm cpacm");
    }

    public void menace(int s) {
        // TODO Auto-generated method stub

    }

    public void kill() {
        // TODO Auto-generated method stub

    }

    public void menace() {
        // TODO Auto-generated method stub

    }

}

tip:切勿過渡設計設計模式

策略模式

p182安全

去商店去買東西,能夠選擇不一樣的出行方式但都能達到買東西的目的,這種選擇模式就是策略模式。
把出行方式抽象爲一個接口,實現公交車,自行車,走路,出租車等實例,最後本身決定使用哪一種方式。框架

策略模式:定義一系列的算法,把每個算法封裝起來, 而且使它們可相互替換。本模式使得算法可獨立於使用它的客戶而變化。也稱爲政策模式(Policy)。策略模式把對象自己和運算規則區分開來,其功能很是強大,由於這個設計模式自己的核心思想就是面向對象編程的多形性的思想。
環境類(Context):用一個ConcreteStrategy對象來配置。維護一個對Strategy對象的引用。可定義一個接口來讓Strategy訪問它的數據。
抽象策略類(Strategy):定義全部支持的算法的公共接口。 Context使用這個接口來調用某ConcreteStrategy定義的算法。
具體策略類(ConcreteStrategy):以Strategy接口實現某具體算法。
策略模式dom

適配器模式

p183
將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠在一塊兒工做。
在Android中經常使用到的各類Adapter就是用的適配器模式思想。
適配器模式ide

工廠模式

p187
工廠模式主要用如下幾種形態:

  1. 簡單工廠(Simple Factory): 主要代碼由一個Factory管理,每添加一個產品都須要在factory類中修改代碼;
  2. 工廠方法(Factory Method):一種產品對應一個工廠,增長一種產品就同時增長一個工廠;
  3. 抽象工廠(Abstract Factory):一般用於多種產品且每種都有不一樣型號的狀況下,針對型號創建工廠,每一個工廠只生產該型號的產品。

抽象工廠和工廠能夠根據不一樣狀況下相互轉化。

第十章(內部類)

1、訪問權

p191
內部類擁有其外圍類的全部元素的訪問權。
意思是經過內部類可以得到其外部類的內存信息(參數值)。
故不能直接經過建立普通對象的方法建立內部類,必需要經過外部類才能建立。

public class DotThis {
    void f() {
        System.out.println("DotThis.f()");
    }

    public class Inner {
        public DotThis outer() {
            return DotThis.this;
            // A plain "this" would be Inner's "this"
        }
    }

    public Inner inner() {
        return new Inner();
    }

    public static void main(String[] args) {
        DotThis dt = new DotThis();
        DotThis.Inner dti = dt.inner();
        dti.outer().f();
    }
}

2、.new

p193
.new語法,能夠直接建立其內部類,但前提也是要提供其外部類的引用。

public class DotNew {

    public class Inner{};

    public static void main(String[] args) {
        DotNew dn = new DotNew();
        DotNew.Inner dti = dn.new Inner();
    }
}

當內部類向上轉型爲基類或接口時,每每是爲了隱藏實現細節。

3、局部

p196
內部類能夠嵌入在任何堆做用域內,但只在其做用域內可用。稱做爲局部內部類

public class Parcel6 {

    private void inTrack(boolean b){
        if(b){
            class TrackSlip{
                private String id;
                TrackSlip(String s){
                    id = s;
                }
                String getSlip(){return id;}
            }
            TrackSlip ts = new TrackSlip("slip");
            String s = ts.getSlip();
        }
    }
    //TrackSlip ts = new TrackSlip("slip"); //run error

    public void track(){
        inTrack(true);
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Parcel6 p = new Parcel6();
        p.track();
    }

}

4、匿名內部類

p200
匿名內部類是一個沒有名字的內部類,一般使用它來簡化代碼編寫,同時必須繼承一個父類或實現一個接口。

public class Parcel7 {

    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }

}
//1 2 3 4 5

tip:經常使用的擴展是將只使用一次的工廠類做爲匿名內部類放在生產類上。

5、嵌套類

p201
將內部類聲明爲static時,此時就做爲嵌套類使用。建立嵌套類的對象並不須要外圍對象,同時也不能從嵌套類的對象中訪問非靜態的外圍對象。

6、接口內部類

p202
在接口中能夠放入嵌套類。

public interface ClassInInterface {

    void howdy();

    class Test implements ClassInInterface{

        @Override
        public void howdy() {
            // TODO Auto-generated method stub
            System.out.println("Howdy!");
        }

        public static void main(String[] args) {
            new Test().howdy();
        }

    }

}

7、內部類做用

p205
使用內部類的一些好處

  1. 能夠解決多重繼承的問題,由於內部類能夠訪問外圍類的信息,因此得到內部類至關於得到外圍類和內部類兩種信息。
  2. 在一個外圍類中,可讓多個內部類以不一樣的方式實現同一個接口或類從而實現不一樣的特性。

8、模版模式

p207
模板方法模式:定義一個操做中算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。
模板模式須要一個抽象類和繼承該抽象類的子類來實現。一樣使用出門買東西的情景:出門->買東西->回來。

咱們不關心怎麼出去和回來,因此把出門和回來的方法寫在抽象類中,而後將買東西這個方法抽象化放在抽象類中以便子類實現。
接着建立子類繼承抽象類,買一種東西能夠建立一個新類,從而實現抽象方法。

而策略模式是使用委託方法實現的,須要一個用來實現
方法的接口存在。
模板模式和策略模式一般能夠互相替換。

9、命令設計模式

p211

命令模式的結構
顧名思義,命令模式就是對命令的封裝,首先來看一下命令模式類圖中的基本結構:
Command類:是一個抽象類,類中對須要執行的命令進行聲明,通常來講要對外公佈一個execute方法用來執行命令。
ConcreteCommand類:Command類的實現類,對抽象類中聲明的方法進行實現。
Client類:最終的客戶端調用類。
以上三個類的做用應該是比較好理解的,下面咱們重點說一下Invoker類和Recevier類。
Invoker類:調用者,負責調用命令。
Receiver類:接收者,負責接收命令而且執行命令。
命令模式的精髓所在:把命令的調用者與執行者分開,使雙方沒必要關心對方是如何操做

10、繼承內部類

p212
當繼承內部類的時候必須在構造器中傳入外圍類的引用和外圍類的super;

第十一章(持有對象)

1、各個容器

p220
ArrayList LinkedList 都是按插入順序存放數據
ArrayList在隨機訪問速度上比較快,而LinkedList在插入和刪除數據比較有優點,具備Queue,Stack的特性。
HashSet TreeSet LinkedHashSet
HashMap TreeMap LinkedHashMap
通用點:Hash開頭的容器都是經過Hash值來查找數據,因此特色是無序但速度快;
Tree開頭的容器都會將存入的數據進行升序排列;
Linked則是按插入的順序進行排序。
(後面17章會介紹其原理)

2、迭代器

p226
迭代器具備如下特性:
1)建立代價小
2)單向移動
3)next()獲取下一個對象,hasNext()判斷是否具備下一個對象,remove()移除當前對象。

(ListIterator做爲List特有的迭代器,具備雙向移動功能,其對應方法爲hasPrevious(),previous())

````java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;

public class CrossContainerIteration {

public static void display(Iterator<Pet> it) {
    while (it.hasNext()) {
        Pet p = it.next();
        System.out.println(p.id() + ":" + p + " ");
    }
    System.out.println();
}

public static void main(String[] args) {
    // TODO Auto-generated method stub
    List<Pet> pets = new ArrayList<>();
    pets.add(new Pet("cat"));
    pets.add(new Pet("dog"));
    pets.add(new Pet("bird"));
    pets.add(new Pet("fish"));
    pets.add(new Pet("pig"));
    LinkedList<Pet> petsLL = new LinkedList<>(pets);
    HashSet<Pet> petsHS = new HashSet<>(pets);
    TreeSet<Pet> petsTS = new TreeSet<>(pets);

    display(pets.iterator());
    display(petsLL.iterator());
    display(petsHS.iterator());
    display(petsTS.iterator());
}

}
/*0:Pet cat
1:Pet dog
2:Pet bird
3:Pet fish
4:Pet pig

0:Pet cat
1:Pet dog
2:Pet bird
3:Pet fish
4:Pet pig

3:Pet fish
1:Pet dog
4:Pet pig
2:Pet bird
0:Pet cat

2:Pet bird
0:Pet cat
1:Pet dog
3:Pet fish
4:Pet pig */
```

2、棧

p230
後進先出
一般可使用LinkedList來實現Stack的功能

public class Stack<T> {
    private LinkedList<T> storge = new LinkedList<>();
    public void push(T v){
        storge.addFirst(v);
    }
    public T peek(){
        return storge.getFirst();
    }

    public T pop(){
        return storge.removeFirst();
    }

    public boolean empty(){
        return storge.isEmpty();
    }

}

3、隊列

p236
Queue 先進先出
一樣可使用LinkedList來實現功能,因爲其實現了Queue接口,能夠將其向上轉型。

public class QueueDemo {
    public static void printQ(Queue queue) {
        while (queue.peek() != null)
            System.out.print(queue.remove() + " ");
        System.out.println();
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<Integer>();
        Random rand = new Random(47);
        for (int i = 0; i < 10; i++)
            queue.offer(rand.nextInt(i + 10));
        printQ(queue);
        Queue<Character> qc = new LinkedList<Character>();
        for (char c : "Brontosaurus".toCharArray())
            qc.offer(c);
        printQ(qc);
    }
} /*
 * Output: 8 1 1 1 5 14 3 1 0 1 B r o n t o s a u r u s
 */

3、優先隊列

p237
PriorityQueue
簡單來講就是具備排序功能的隊列,下一個彈出的元素是在隊列中優先級最高的一個。使用Comparator比較器來進行比較。

public class PriorityQueueDemo {
    public static void main(String[] args) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>();
        Random rand = new Random(47);
        for (int i = 0; i < 10; i++)
            priorityQueue.offer(rand.nextInt(i + 10));
        QueueDemo.printQ(priorityQueue);

        /*
        * Output: 0 1 1 1 1 1 3 5 8 14 1 1 2 3 3 9 9 14 14 18 18 20 21 22 23 25 25 25
        */

        List<Integer> ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2,
                3, 9, 14, 18, 21, 23, 25);
        priorityQueue = new PriorityQueue<Integer>(ints);
        QueueDemo.printQ(priorityQueue);
        priorityQueue = new PriorityQueue<Integer>(ints.size(),
                Collections.reverseOrder());
        priorityQueue.addAll(ints);
        QueueDemo.printQ(priorityQueue);

        /*
        * 25 23 22 21 20 18 18 14 14 9 9 3 3 2 1 1 
        */


        String fact = "EDUCATION SHOULD ESCHEW OBFUSCATION";
        List<String> strings = Arrays.asList(fact.split(""));
        PriorityQueue<String> stringPQ = new PriorityQueue<String>(strings);
        QueueDemo.printQ(stringPQ);
        stringPQ = new PriorityQueue<String>(strings.size(),
                Collections.reverseOrder());
        stringPQ.addAll(strings);
        QueueDemo.printQ(stringPQ);

        Set<Character> charSet = new HashSet<Character>();
        for (char c : fact.toCharArray())
            charSet.add(c); // Autoboxing
        PriorityQueue<Character> characterPQ = new PriorityQueue<Character>(
                charSet);
        QueueDemo.printQ(characterPQ);
    }
        /*
        * A A B C C C D D E E E F H H I I L N
        * N O O O O S S S T T U U U W W U U U T T S S S O O O O N N L I I H H F E E E D
        * D C C C B A A A B C D E F H I L N O S T U W
        */

}

總結:四種容器List Set Queue Map

第十二章(經過異常處理錯誤)

Java的基本理念是「結構不佳的代碼不能運行

自定義異常

p252
咱們能夠繼承Exception類來自定義異常,在自定義異常類中能夠添加一些動做,好比寫入日誌等等。

class MyException extends Exception {
  public MyException() {}
  public MyException(String msg) { super(msg); }
}

public class FullConstructors {
  public static void f() throws MyException {
    System.out.println("Throwing MyException from f()");
    throw new MyException();
  }
  public static void g() throws MyException {
    System.out.println("Throwing MyException from g()");
    throw new MyException("Originated in g()");
  }
  public static void main(String[] args) {
    try {
      f();
    } catch(MyException e) {
      e.printStackTrace(System.out);
    }
    try {
      g();
    } catch(MyException e) {
      e.printStackTrace(System.out);
    }
  }
} /* Output:
Throwing MyException from f()
MyException
        at FullConstructors.f(FullConstructors.java:11)
        at FullConstructors.main(FullConstructors.java:19)
Throwing MyException from g()
MyException: Originated in g()
        at FullConstructors.g(FullConstructors.java:15)
        at FullConstructors.main(FullConstructors.java:24)
*///:~

異常也是類的一種,因此咱們能夠擴展使其得到更強大的功能。

class MyException2 extends Exception {
    private int x;

    public MyException2() {
    }

    public MyException2(String msg) {
        super(msg);
    }

    public MyException2(String msg, int x) {
        super(msg);
        this.x = x;
    }

    public int val() {
        return x;
    }

    public String getMessage() {
        return "Detail Message: " + x + " " + super.getMessage();
    }
}

public class ExtraFeatures {
    public static void f() throws MyException2 {
        System.out.println("Throwing MyException2 from f()");
        throw new MyException2();
    }

    public static void g() throws MyException2 {
        System.out.println("Throwing MyException2 from g()");
        throw new MyException2("Originated in g()");
    }

    public static void h() throws MyException2 {
        System.out.println("Throwing MyException2 from h()");
        throw new MyException2("Originated in h()", 47);
    }

    public static void main(String[] args) {
        try {
            f();
        } catch (MyException2 e) {
            e.printStackTrace(System.out);
        }
        try {
            g();
        } catch (MyException2 e) {
            e.printStackTrace(System.out);
        }
        try {
            h();
        } catch (MyException2 e) {
            e.printStackTrace(System.out);
            System.out.println("e.val() = " + e.val());
        }
    }
} /*
 Throwing MyException2 from f()
chapter12.MyException2: Detail Message: 0 null
    at chapter12.ExtraFeatures.f(ExtraFeatures.java:32)
    at chapter12.ExtraFeatures.main(ExtraFeatures.java:47)
Throwing MyException2 from g()
chapter12.MyException2: Detail Message: 0 Originated in g()
    at chapter12.ExtraFeatures.g(ExtraFeatures.java:37)
    at chapter12.ExtraFeatures.main(ExtraFeatures.java:52)
Throwing MyException2 from h()
chapter12.MyException2: Detail Message: 47 Originated in h()
    at chapter12.ExtraFeatures.h(ExtraFeatures.java:42)
    at chapter12.ExtraFeatures.main(ExtraFeatures.java:57)
e.val() = 47
 */// :~

p257
全部的異常均可以由Exception進行捕獲,能夠經過Exception打印發生錯誤時所獲取的信息。

Rethrow

p258
能夠經過throw將catch到的異常從新拋出,不過異常裏面是原來異常拋出的調用棧信息。可使用 fillInStackTrace()更新,調用 fillInStackTrace那一行就成了異常的新發生地。

public class Rethrowing {
  public static void f() throws Exception {
    System.out.println("originating the exception in f()");
    throw new Exception("thrown from f()");
  }
  public static void g() throws Exception {
    try {
      f();
    } catch(Exception e) {
      System.out.println("Inside g(),e.printStackTrace()");
      e.printStackTrace(System.out);
      throw e;
    }
  }
  public static void h() throws Exception {
    try {
      f();
    } catch(Exception e) {
      System.out.println("Inside h(),e.printStackTrace()");
      e.printStackTrace(System.out);
      throw (Exception)e.fillInStackTrace();
    }
  }
  public static void main(String[] args) {
    try {
      g();
    } catch(Exception e) {
      System.out.println("main: printStackTrace()");
      e.printStackTrace(System.out);
    }
    try {
      h();
    } catch(Exception e) {
      System.out.println("main: printStackTrace()");
      e.printStackTrace(System.out);
    }
  }
} /* Output:
originating the exception in f()
Inside g(),e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:7)
        at Rethrowing.g(Rethrowing.java:11)
        at Rethrowing.main(Rethrowing.java:29)
main: printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:7)
        at Rethrowing.g(Rethrowing.java:11)
        at Rethrowing.main(Rethrowing.java:29)
originating the exception in f()
Inside h(),e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:7)
        at Rethrowing.h(Rethrowing.java:20)
        at Rethrowing.main(Rethrowing.java:35)
main: printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.h(Rethrowing.java:24)
        at Rethrowing.main(Rethrowing.java:35)
*///:~

異常鏈

p260
Throwable的子類能夠接受一個cause對象做爲參數,cause表示原始異常,這樣能夠經過把原始異常傳遞給新的異常使得能夠追蹤全部鏈接起來的異常。
在Throwable子類中,只有三種基本的異常類提供了帶cause參數的構造器,分別爲Error,Exception和RuntimeException。若是要把其餘類型的異常連接起來,應該使用initCause()方法。

return

p268
return 與 fianl共用時,即便在try裏面實行return,finally裏面的代碼仍是會運行,
而在final裏面使用熱力return 的話,即便拋出了異常也不會產生任何輸出。

異常使用指南

p281

  1. 在恰當的級別處理問題。
  2. 解決問題而且從新調用產生異常的方法。
  3. 進行少量修補,而後繞過異常發生的地方繼續執行。
  4. 用別的數據進行計算,以代替異常發生的地方繼續執行。
  5. 吧當前運行環境下能作的事情儘可能作完,而後將相同的異常重拋到更高層。
  6. 吧當前運行環境下能作的事情儘可能作完,而後將不一樣的異常重拋到更高層。
  7. 終止程序
  8. 進行簡化。
  9. 藍類庫和程序更安全。

《Java編程思想》閱讀筆記一

相關文章
相關標籤/搜索