天天看點

Java匿名内部類與回調函數

    之是以将匿名内部類和回調函數兩個知識點一起寫,是因為最近學習zookeeper的時候正好遇到這麼一個例子。詳細内容請參考:https://www.w3cschool.cn/zookeeper/zookeeper_api.html

以下是與ZooKeeper集合連接配接的完整代碼。

public class ZooKeeperConnection {

   // declare zookeeper instance to access ZooKeeper ensemble
   private ZooKeeper zoo;
   final CountDownLatch connectedSignal = new CountDownLatch(1);

   // Method to connect zookeeper ensemble.
   public ZooKeeper connect(String host) throws IOException,InterruptedException {
	
      zoo = new ZooKeeper(host,5000,new Watcher() {
		
         public void process(WatchedEvent we) {

            if (we.getState() == KeeperState.SyncConnected) {
               connectedSignal.countDown();
            }
         }
      });
		
      connectedSignal.await();
      return zoo;
   }

   // Method to disconnect from zookeeper server
   public void close() throws InterruptedException {
      zoo.close();
   }
}           

匿名内部類的建立格式如下:

new 父類構造器(參數清單)|實作接口()  
    {  
     //匿名内部類的類體部分  
    }           

在上面的代碼中,connect方法中在執行個體化ZooKeeper對象時用到了匿名内部類:

zoo = new ZooKeeper(host,5000,new Watcher() {
		
         public void process(WatchedEvent we) {

            if (we.getState() == KeeperState.SyncConnected) {
               connectedSignal.countDown();
            }
         }
      });           

這個内部類沒有自己的名字,而是用到了Watcher接口,而通常情況下接口是不能用new的,但是在匿名内部類中可以這樣。匿名内部類的類體是一個名為process的方法,這個方法就是用來實作Watcher接口中定義的process抽象方法的。

在這個匿名内部類中恰好又運用了回調函數(又叫回調方法)。

回調是一種常見的程式設計模式。

在這種模式中,可以指出某個特定事件發生時應該采取的動作。

ZooKeeper類通過其構造函數提供connect功能。構造函數的簽名如下 :

ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher)

在上面的類ZooKeeperConnection中,connect 方法建立一個ZooKeeper對象,連接配接到ZooKeeper集合,然後傳回對象。

在此處使用CountDownLatch,就是為了形成一個回調函數。一開始将CountDownLatch對象connectedSignal值設為CountDownLatch(1);如果匿名内部類中的if語句不為真,這意味着下面的主線程會在一直處于等待狀态,停留在connectedSignal.await();處。這個就恰好符合了回調函數的意義:

在某個特定事件發生時應該采取的動作。 如果用戶端與Zookeeper沒有成功建立連接配接(也就是if語句不為真),就不傳回ZooKeeper對象zoo(在 connectedSignal.await()停留)。而一旦成功建立連接配接 (也就是if語句為真,執行connectedSignal.countDown()) ,就傳回 ZooKeeper對象zoo ( connectedSignal.await()放行)

将匿名内部類改為普通類

在上述代碼中可以将匿名内部類拆出來,作為一個單獨類:XyzWatcher

public class XyzWatcher implements Watcher {
    @Override
    public void process(WatchedEvent watchedEvent) {
        final CountDownLatch connectedSignal = new CountDownLatch(1);
        if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
            connectedSignal.countDown();
        }
        try {
            connectedSignal.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}           

原來的類ZooKeeperConnection改為如下:

public class ZooKeeperConnection {

    // declare zookeeper instance to access ZooKeeper ensemble
    private ZooKeeper zoo;
    //public final CountDownLatch connectedSignal = new CountDownLatch(1);

    // Method to connect zookeeper ensemble.
    XyzWatcher xyz = new XyzWatcher();

    public ZooKeeper connect(String host) throws IOException,InterruptedException {
        zoo = new ZooKeeper(host,5000,xyz);
        return zoo;
    }

    // Method to disconnect from zookeeper server
    public void close() throws InterruptedException {
        zoo.close();
    }
}