2014-03-29 106 views
1

NOTE:我知道這是危險地接近許多其他問題。然而,我沒有看到任何特別與Android的OnClickListener接口有關的東西。我在一般意義上問。通過匿名類擴展接口VS實例化

我明白通過一個匿名類... 一拉實例化一個接口的區別:和擴展接口

private final Runnable runnable = new Runnable() { 
    @Override 
    public void run() { 
     draw(); 
    } 

}; 

...。

public class ClassyClass implements Runnable { 
    ... 
    //do other cool stuff here 
    ... 
    @Override 
    public void run() { 
     draw(); 
    } 
    ... 
    //and more here 
    ... 

} 

但是,除了從諸如OnClickListener接口的明顯好處是有很強的優勢,以任一選項?

我認爲擴展它將是明顯的選擇,因爲您已經創建了該對象 - 不需要重複工作。這是正確的嗎?

我問在一般意義上,但是,因爲我目前Runnable工作,如果它已經從任一選項我很想知道看到一個優勢。

回答

2

那麼這裏是顯示的主要差別的例子。這有點做作,但只是爲了說明。

下面是一個匿名版本:

class PrintBuilder { 
    List<Runnable> printers = new LinkedList<>(); 

    List<Runnable> get() { 
     return printers; 
    } 

    PrintBuilder add(final String line) { 
     printers.add(new Runnable() { 
      public void run() { 
       System.out.println(line); 
      } 
     }); 

     return this; 
    } 
} 

這裏是一個嵌套的版本:

class PrintBuilder { 
    List<Printer> printers = new LinkedList<>(); 

    PrintBuilder add(String line) { 
     printers.add(new Printer(line)); 
     return this; 
    } 

    List<Printer> get() { 
     return printers; 
    } 

    static class Printer implements Runnable { 
     String line; 

     Printer(String line) { 
      this.line = line; 
     } 

     public void run() { 
      System.out.println(line); 
     } 
    } 
} 

所以,你可以看到主要的區別是,則:

  • 匿名類是內部,它有一個隱式引用封閉的實例。

特別是,在上面的例子中,PrintBuilder被泄漏,直到內部Runnable對象死亡。在第二個例子中,Runnable類是靜態的,所以它沒有這個問題。

  • 匿名類短一點。

匿名類不需要字段和構造函數,因爲它們是隱式的。

  • 代碼組織方式的巨大差異。

一個匿名類被聲明在實例化的地方,如果匿名類不是非常短,這對封閉類的佈局可能具有相當的破壞性。另一方面,如果匿名類很短,功能類語法就很好。

同樣所有的課程都會增長,以我的經驗,當匿名課程變得太大時,這會變成一種氣味。匿名類更難以重構到頂級類。

+0

非常感謝。我讚賞具體的贊成/反對。最後一個問題。我有點得到它,我已經看到其他人談論泄漏(在前1),但你能具體解釋爲什麼它發生? – BrassApparatus

+1

@BrassApparatus:發生這種情況的原因是,內部類通過設計隱式引用其封閉對象,以便能夠訪問其字段和方法。就像在第二個示例的打印機中有一個PrintBuilder字段,並將'this'作爲Printer構造函數的參數傳遞。 –

+0

@JBNizet陷阱,謝謝。我感謝所有的幫助。 – BrassApparatus

0

第一個片段定義了一個沒有名字的類,它實現了Runnable接口(並實例化了匿名類)。第二個定義了一個具有名稱的類,該類還實現了Runnable接口。

在繼承和接口實現方面沒有區別,除了第二個類有一個名稱,第一個沒有名稱。

第二個代碼片段允許多個類實例化Runnable實現,而第一個代碼段定義一個只能從其封閉類中知道的類。有時候一個更好,有時另一個更好。

0

這兩種方法都是有效的。使用哪一個取決於你的用法:

  • 如果你在另一個類中實現一個接口,你將有權訪問父類的protected和private方法。
  • 如果您想保持事物分離並重復使用此接口的相同實現,則創建一個單獨的類是一種可行的方法。