2012-03-08 83 views
32

我有一個很簡單的問題:Java最終抽象類

我想要一個Java類,它提供了一個公共靜態方法,它執行某些操作。這僅僅是爲了封裝目的(在一個單獨的類中具有一切重要性)...

這個類既不應該被實例化,也不應被擴展。這讓我寫:

final abstract class MyClass { 
    static void myMethod() { 
     ... 
    } 
    ... // More private methods and fields... 
} 

(雖然我知道,這是禁止的)。

我也知道,我可以讓這個類完全是最終的,並在使其隱藏時重寫標準構造函數。

但是,這在我看來,更像是一個「解決辦法」,應更有可能最終抽象類來完成...

我討厭的解決方法。所以僅僅爲了我自己的利益:有沒有更好的方法?

+0

單身模式? – 2012-03-08 13:46:26

+5

爲什麼你想讓課堂抽象?抽象類意味着有一些已聲明但未實現的方法,其中**擴展類** _必須實現。 – 2012-03-08 13:46:43

+5

@Aleks G:這不是真的......抽象類的意思是:你不能直接實例化它。你不一定需要在該類中定義抽象方法......當然你是對的。通常你會像你說的那樣使用抽象類。但這只是一個「觀點」的東西。我總是在不定義抽象方法的情況下製作抽象的大型工廠類。 – Sauer 2012-03-08 14:36:19

回答

42

參考:有效的Java第二版第4項

public final class MyClass { //final not required but clearly states intention 
    //private default constructor ==> can't be instantiated 
    //side effect: class is final because it can't be subclassed: 
    //super() can't be called from subclasses 
    private MyClass() { 
     throw new AssertionError() 
    } 

    //... 
    public static void doSomething() {} 
} 
+39

@LuiggiMendoza這不是一個單身模式。這裏根本沒有實例。 – 2012-03-08 13:50:24

+0

是的,但Singleton Pattern可能是一個合適的解決方案。 – 2012-03-08 13:52:38

+0

我想讓它成爲'final',這並不是因爲JDK6/J2SE 5.0有什麼不同。 – 2012-03-08 14:08:08

4

否「與私有構造強制noninstantiability」,抽象類是爲了進行擴展。使用私有構造函數,這不是一種解決方法 - 這是做到這一點的方法!

6

不,你應該做的是創建一個私有的空構造函數,在它的正文中引發一個異常。 Java是一種面向對象的語言,而永遠不會被實例化的類本身就是一種解決方法! :)

final class MyLib{ 
    private MyLib(){ 
     throw new IllegalStateException("Do not instantiate this class."); 
    } 

    // static methods go here 

} 
+0

@assylias:*「班級將是最終的,因爲它不能被分類」*。這取決於你對「最終」的定義。這並不像是因爲私有構造函數而被隱式創建的* final *(例如,未聲明爲public的接口方法是隱式公開的)。舉例來說,* public final *或者簡單地* public * **將導致生成兩個不同的* .class *文件:* final * * .class *將其訪問標誌設置爲0x31(public final)只有*公共*其訪問標誌是0x21。你不能擴展它,但它仍然不是* final * ... – TacticalCoder 2012-03-08 14:14:55

+0

@ArtB但是你會同意,下面也是nonsens ?:另一種方法是,編寫一個「object-class」並調用構造函數一次,其中做所有的工作......沒有進一步使用這個對象的意義。它沒有析構函數,沒有getter,也沒有setter ...在這種情況下,對象是毫無意義的,因爲所有的對象都是完全相同的。這正是靜態方法的用途。將東西封裝到分離的類(即「文件」)是一種很好的做法。當然,我可以把所有東西都放在我的電話班。但是這樣做太多了...... – Sauer 2012-03-08 14:30:59

+0

@Sauer在不知道具體情況的情況下很難提供替代方案,但在改進面向對象設計原則之後,我發現很少需要靜態方法。我真正可以證明的唯一情況是那些你正在添加應該存在於課堂中的方法或者用於處理空問題的方法。 – ArtB 2012-03-08 15:13:09

45

你不能比沒有實例使用enum簡單得多。

public enum MyLib {; 

    public static void myHelperMethod() { } 
} 

該類是final的,沒有明確的實例和私有構造函數。

這是由編譯器檢測到的,而不是運行時錯誤。 (不像拋出異常)

+8

它是完美的解決方案。我不明白爲什麼人們不投票。 – AlexR 2012-03-08 14:01:36

+2

@AlexR我也爲同樣的原因使用枚舉的單身人士。您明確指出可以有多少個實例。 'enum'可以在單例情況下擴展接口。 – 2012-03-08 14:03:37

+4

Peter Lawrey 1 - 0 Joshua Bloch ;-)(有趣的是,JB沒有提及,當他主張對單例使用枚舉時如此強烈) – assylias 2012-03-08 14:04:33

1

assylias(所有Java版本)和Peter Lawrey(> = Java5)的建議是在這種情況下的標準方式。

但是,我想提醒您注意,防止靜態實用程序類的擴展是一個非常最後的決定,可能會在以後出現,當您發現在不同的項目中有相關的功能時實際上是想擴展它。

我建議如下:

public abstract MyClass { 

    protected MyClass() { 
    } 

    abstract void noInstancesPlease(); 

    void myMethod() { 
     ... 
    } 
    ... // More private methods and fields... 

} 

這正好慣例,因爲它允許類的擴展需要的時候,它還是防止意外的實例(你甚至不能沒有創建一個匿名子類的實例得到一個非常明確的編譯器錯誤)。

它總是我認爲JDK的實用類(如java.util.Arrays)實際上是最終的。如果你想讓你擁有自己的Arrays類,並且有可以比較的方法,那麼你不能,你必須創建一個單獨的類。這將分發(IMO)所屬的功能,並應通過一個類提供。這會讓你使用分佈廣泛的實用程序方法,或者你必須將每一種方法都複製到自己的類中。

我建議永遠不要讓這樣的工具類最終。在我看來,這些優勢並沒有超出我的缺點。

+0

我明白了你的觀點,並讓我思考我的設計。但就我而言,我真的不想讓別人延長我的課程。這就是爲什麼它是默認可見性「final class MyClass」(沒有公開)。它只在我的軟件包內有效,任何人都不能在該軟件包之外使用它。沒有人應該能夠將其擴展到包裝內。但無論如何:用「noInstancesPlease」抽象方法的好主意......我會記住這一點 – Sauer 2012-03-13 14:42:38

2

聲明類的構造函數是private。這確保了不可用性並防止子類化。

0

您不能將類標記爲抽象類和最終類。它們幾乎與 的含義相反。一個抽象類必須被分類,而最後一個類不能被分類爲 。如果您看到用於類或方法聲明的抽象和最終修飾符的組合,代碼將無法編譯。

-1

這是簡單的英語解釋。一個抽象類不能被實例化,只能被擴展。最終的類不能被擴展。現在如果你創建一個抽象類作爲最終的類,你怎麼認爲你是一個抽象類,我們會不會使用這個班級,實際上,首先要把自己置於這樣一個陷阱裏的理由是什麼?

+1

你是對的。但是,正如我所說:我想用這個類來創建一個靜態方法的工具箱。所以我既不想安撫,也不想延長它。 – Sauer 2016-05-30 10:04:00