Java源码分析——java.util工具包解析(五)——UUID、Base64、内置观察者模式Observer接口、EventListener、RandomAccess

版权声明:博主GitHub地址https://github.com/suyeq欢迎大家前来交流学习 https://blog.csdn.net/hackersuye/article/details/84495594

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();

    这样就把代码间的模块清晰化了,是代码的复用以及可拓展性大大的提高了。

猜你喜欢

转载自blog.csdn.net/hackersuye/article/details/84495594