簡體   English   中英

匿名與命名內部類? - 最佳實踐?

[英]Anonymous vs named inner classes? - best practices?

我有一個類,我們稱之為 LineGraph,它呈現一個折線圖。 我需要對它進行子類化,但派生類只在一個地方使用,並且與使用它的類耦合。 所以我正在使用一個內部類。

我看到兩種方法可以做到這一點:

匿名內部類

public class Gui {
    LineGraph graph = new LineGraph() {
        // extra functionality here.
    };
}

命名內部類

public class Gui {
    MyLineGraph graph = new MyLineGraph();

    private class MyLineGraph extends LineGraph {
        // extra functionality here.
    }
}

我不是匿名內部類的粉絲,因為坦率地說,我只是覺得它看起來很丑。 但是對於只在一個地方使用的子類,命名內部類是否過大? 公認的做法是什么?

匿名內部類的一個優點是沒有人可以在其他任何地方使用它,而可以使用命名的內部類(如果只有創建它的類如果設為私有)。 這是一個很小的區別,但這確實意味着您可以保護內部類不被意外使用到其他地方。

此外,使用匿名內部類可以讓任何閱讀您的代碼的人都振作起來——“這個類只在這里使用,其他任何地方都沒有。” 如果你看到一個命名的內部類,有人可能會認為它會在類中的多個地方使用。

它們非常相似,所以這兩點都不會改變游戲規則。 我只是認為,如果您一次性使用匿名內部類,並在類中多次使用它時命名內部類,這有助於清晰。

(反駁丹尼爾·盧)

匿名內部類的一個缺點是沒有人可以在其他任何地方使用它,而可以使用命名的內部類(如果只有創建它的類如果設為私有)。 這是一個很小的區別,但這確實意味着您可以幫助確保內部類不會在其他地方意外重新創建。

此外,使用匿名內部類會使任何人閱讀您的代碼更加困難,因為他們必須解析這個不知從何而來的類。 使用命名的內部類,您可以更多地組織源代碼。

我見過有兩個(或更多)匿名內部類具有完全相同代碼的情況。 特別是在 GUI 中(您可能有多個控件執行相同的操作),這可能會突然出現(我說的是生產代碼,而不是我的學生編寫的代碼)。

可讀性問題是雙向的,有些人發現匿名內部類更好,因為它可以讓你看到一個地方發生了什么,而另一些人則認為它會分散注意力。 這部分歸結為個人喜好。

同樣使類靜態更有效,如果您在實例中聲明匿名內部類,那么將會有更多開銷,如果您不需要訪問實例變量,這是浪費的(但可能不值得擔心直到它出現問題)。

我個人的偏好是使用非匿名類,因為它們在以后修改代碼時允許更大的靈活性。

為什么需要對它進行子類化? 如果只是覆蓋現有的虛方法,我覺得匿名內部類是可以的。 如果您要添加額外的功能,我會使用命名類。 不過,我會將其設為嵌套類(即使用static修飾符)-我發現它們更容易推理:)

做可能可行的最簡單的事情:使用匿名內部類。

如果您后來發現需要更廣泛的范圍,請重構代碼以支持這一點。

(你可以對變量做同樣的事情——把它們放在最具體的范圍內。對其他源資產做同樣的事情是有意義的。)

我個人的經驗法則:如果匿名內部類要小,請堅持使用匿名類。 小被定義為大約 20 - 30 行或更少。 如果它會更長,我認為它開始變得不可讀,所以我將它命名為內部類。 我記得曾經看過一個 4000+ 行的匿名內部類。

匿名內部類很難在 Eclipse 中調試(這就是我使用的)。 您將無法通過簡單的右鍵單擊來查看變量值/注入值。

內部類的一個缺點是它們不能是靜態的。 這意味着它將持有對包含它們的外部類的引用。

非靜態內部類可能是一個問題。 例如,我們最近有一個內部類被序列化,但外部類不可序列化。 隱藏的引用意味着外部類也將被序列化,這當然失敗了,但需要一段時間才能找出原因。

在我工作的地方,我們的編碼最佳實踐(如果可能)鼓勵​​靜態內部類,因為它們攜帶的隱藏包袱更少並且更精簡。

匿名類不能有構造函數,因為它們沒有名字。 如果您需要傳遞其他變量而不是您要擴展的類的構造函數中的變量,則應使用(靜態)命名的內部類。 這有時可以通過在周圍的方法/代碼中使用最終變量來克服,但這有點難看恕我直言(並且可能導致 Robin 所說的)。

匿名內部類通常是要走的路。 我發現它們非常具有可讀性。 但是,如果該類的實例需要序列化(即使只是因為它是其他東西的字段),我強烈建議使用命名內部類。 字節碼中匿名內部類的名稱很容易更改,這可能會破壞序列化。

匿名類:

  • 定義中不能有任何static的東西(靜態類、靜態字段、靜態初始化器等)
  • 無法在 Eclipse 中檢查字段
  • 不能用作類型( Foo$1 myFoo=new Foo$1(){int x=0;}不起作用)
  • 無法使用 Eclipse 中的類名定位(搜索Foo$1對我不起作用)
  • 不能重復使用

然而,匿名類可以有一個像{super.foo(finalVariable+this.bar);}這樣的初始化器

命名內部類沒有這些限制,但即使一個專門用於一個長過程的中間,聲明也必須向上移動到下一個命名類。

如果限制不適用,我個人更喜歡匿名內部類,因為:

  • 我知道任何其他字段僅在類定義中引用。
  • Eclipse 可以輕松地將它們轉換為嵌套類。
  • 我不需要復制我想使用的變量。 我可以將它們聲明為最終並引用它們。 當我有很多參數時,這特別有用。
  • 交互的代碼緊密相連。

我對簡單的匿名類沒有問題。 但如果它由多於幾行代碼或幾個方法組成,內部類就更清晰了。 我還認為,在某些情況下,它們永遠不應該被使用。 比如當他們必須返回數據時。

我看過代碼,其中使用 1 個項目的最終數組將數據從調用傳遞回匿名內部類。 在 anon 類的方法中,設置單個元素,然后在方法完成后提取此“結果”。 有效但丑陋的代碼。

今天剛和我的同事討論過這個問題,正在四處尋找流行的意見。

我同意 TofuBeer。 如果您的代碼超過 2 行,它可能不是“一次性的”,並且可能有一天會被重用。 如果您使用 MVC 模式創建表單,則頁面上可能有 20 個可控制元素,而不是用大量匿名類使視圖混亂(見鬼,您的視圖可能是使用 GUI 構建器創建的,並且代碼是自動生成的編輯源甚至不是一個選項)您可能會將每個元素提供給控制器。 您可以在控制器中嵌套內部類以處理視圖所需的每個不同的處理程序/偵聽器接口。 這很好地組織了代碼,特別是如果您的處理程序類必須使用 GUI 元素名稱命名(如 backButtonHandler 用於 backButtonElement)。 這對我們來說非常有效,我們編寫了一個自動注冊工具(當您在視圖上注冊控制器時,視圖使用元素名稱查找內部類並將它們用於每個命名元素的處理程序)。 這對於匿名類是不可能的,並且使控制器更易於回收。

TLDR:如有疑問,請編寫一個命名的內部類。 您永遠不會知道有一天是否有人想重用您的代碼(除非它是 2 行代碼,否則您必須想知道“這段代碼有味道嗎?”)。 從長遠來看,組織良好的代碼具有更高的好處,尤其是在您的項目處於維護狀態時。

使用匿名內部類,我們無法更改包含類成員的狀態。 他們需要被宣布為最終的。

我認為在這種情況下你所做的一切都非常有意義,無論你怎么看,我認為你真的在為這個特殊問題而煩惱。 它們都非常相似,並且都可以工作。

我認為這是一個品味問題。 我更喜歡對Functors使用匿名類。 但在你的情況下,我會使用一個內部類,因為我認為你將在其中打包不僅僅是幾行代碼,也許不僅僅是一個方法。 它會強調這樣一個事實,即通過將其放在類中而不是隱藏在方法中的某個位置,它正在向超類添加功能。 另外,誰知道呢,也許有一天你可能需要其他地方的子類。 當然,這取決於您對軟件將如何發展的了解程度。 除此之外,只需擲硬幣。 :)

嗯,主要的是創建一個匿名內部類比創建一個新的單獨類更快。 當您只需要覆蓋超類中的少量功能(例如一個方法)並且不想處理為如此簡單的事情創建整個類的開銷時,匿名內部類特別有用

請參閱java-anonymous-class-exampleanonymous-class-interface

匿名類使您能夠使您的代碼更簡潔。 它們使您能夠同時聲明和實例化一個類。 它們類似於本地類,只是它們沒有名稱。 如果您只需要使用一次本地類,請使用它們

官方文件

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM