1. 程式人生 > >Java原始碼分析——java.util工具包解析(五)——UUID、Base64、內建觀察者模式Observer介面、EventListener、RandomAccess

Java原始碼分析——java.util工具包解析(五)——UUID、Base64、內建觀察者模式Observer介面、EventListener、RandomAccess

UUID

    關於UUID,我們需要知道它最重要的一點,就是它會生成全地球唯一的一個id,它可以作為資料庫的主鍵存在,標識各個元組。 UUID保證對在同一時空中的所有機器都是唯一的,利用機器的當前日期和時間、時鐘序列、全域性唯一的IEEE機器識別號來生成唯一的一個id。其用法如下:

//得到一個UUID
System.out.println(UUID.randomUUID());

Base64

    Base64類是將不是ASCII碼的字串轉換為ASCII碼格式的,可以做到簡單的將密碼的明文轉變為非明文,但不能做到保密,一般用在網路傳輸上,需要ASCII碼的地方,用法如下:

		//編碼
        String asB64 = Base64.getEncoder().encodeToString("蕾姆".getBytes("utf-8"));
        System.out.println(asB64); // 輸出為: c29tZSBzdHJpbmc=
        // 解碼
        byte[] asBytes = Base64.getDecoder().decode("6JW+5aeG");
        //輸出:6JW+5aeG
		//蕾姆

Observer

    Observer類是Java內建的觀察者模式,用一張圖來說明下觀察者模式:
在這裡插入圖片描述


    對觀察者模式舉個例子的話,就像微信的推送訊息,每個微信的使用者都是觀察者,公眾號就是一個被觀察者,當公眾號有訊息更新後,會同步通知每個觀察者說我要進行訊息的推送了,然後將訊息推送給每個觀察者。可以理解為廣播模式,被觀察者通過廣播通知各個觀察者。在Java中,定義了一個Observer介面,定義了訊息的更新操作:

public interface Observer {
    void update(Observable o, Object arg);
}

    接著是被觀察者:

public
class Observable { //changed表示是否需要更新 private boolean changed = false; //存貯觀察者 private Vector<Observer> obs; public Observable() { obs = new Vector<>(); } //增加一個觀察者 public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } //刪除一個觀察者 public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } //通知所有觀察者 public void notifyObservers() { notifyObservers(null); } //通知所有的觀察者 public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } //刪除所有的觀察者 public synchronized void deleteObservers() { obs.removeAllElements(); } //表明可以進行更新 protected synchronized void setChanged() { changed = true; } //更新完設定不可更新 protected synchronized void clearChanged() { changed = false; } //返回是否更新 public synchronized boolean hasChanged() { return changed; } //觀察者的數量 public synchronized int countObservers() { return obs.size(); } }

    從原始碼中看出,該類是個同步類,執行緒安全,每次更新完都會設定不可更新。如何用這兩個類實現一個觀察者模式呢?首先,先定義觀察者類實現Observer介面,我在這定義了DateUpdateObserver資料更新以及ViewUpdateObserver檢視更新:

public class ViewUpdateObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("檢視改變了");
    }
}

public class DateUpdateObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("資料改變了");
    }
}

    接著實現被觀察者繼承Observable 類,因為設定可以更新的方法是保護方法,所以必須繼承Observable 類來設定可以更新的值,,我這裡為了簡便直接在構造器裡面設定了:

public class ShowUpdate extends Observable {
    public ShowUpdate(){
        setChanged();
    }
}

    測試:

Observable observable=new ShowUpdate();
observable.addObserver(new DateUpdateObserver());
observable.addObserver(new ViewUpdateObserver());
observable.notifyObservers();
//輸出:檢視改變了  資料改變了

EventListener、RandomAccess

    關於這兩個介面,閱讀過它兩原始碼的同學都知道,它們都是空的介面,沒有定義任何東西,是起標記用的:

public interface RandomAccess {
}
public interface EventListener {
}

    先說RandomAccess介面,該介面是一個標記為隨機訪問的介面,是什麼意思呢?RandomAccess介面被ArrayList、Vector實現過,是讓它判斷是否是陣列型別的容器的,因為只有陣列型別的容器可以用下標來實現隨機的訪問。這一點用到了Collections容器的選擇查詢對應值的索引上:

public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }

    從原始碼中看出,當容器實現了RandomAccess 介面時,用索引值查詢的方式來進行二分搜尋,否則就用迭代器來進行,因為陣列型別的容器,即ArrayList的索引值查詢比迭代器查詢快很多。

    而EventListener介面可以用來實現自定義的監聽器,試想一個網路請求資料的非同步場景,當你向伺服器請求時,假如這個請求是非同步的請求,伺服器並不會立馬返回,而是需要等待一會兒,這時候你就要寫個監聽來監聽它的資料的返回,我們可以利用這個介面來實現:

public interface NetworkListener extends EventListener {
    void success();
    void fail();
}

public class NetworkListenerIml  implements NetworkListener{
    @Override
    public void success() {
        System.out.println("成功了");
    }

    @Override
    public void fail() {
        System.out.println("失敗了");
    }
}

public class NetworkRequest {
    private NetworkListener eventListener;
    public void addEventListener(NetworkListener eventListener){
        this.eventListener=eventListener;
    }

    public void request(){
        eventListener.success();
    }
}

NetworkRequest networkRequest=new NetworkRequest();
       networkRequest.addEventListener(new NetworkListenerIml());
       networkRequest.request();

    這樣就把程式碼間的模組清晰化了,是程式碼的複用以及可拓展性大大的提高了。