2012-09-03 40 views
6

我是Java新手。有一件事讓我困惑,爲什麼有些類需要new實例化,以及爲什麼其他一些類不需要new實例化。爲什麼有些類在創建實例時不需要「新建」一詞?

例如,我在看log4j,它不需要new

爲什麼其他一些類需要新的?例如,一個Employee類:

Employee X = new Employee (John); 
X.getwork(); 

等等等等

爲什麼我們不說,Logger logger = new Logger(...);?爲什麼我們能夠使用它,即使沒有new,就像logger.setLevel()

+3

[工廠方法模式](http://en.wikipedia.org/wiki/Factory_method_pattern) – oldrinb

+0

'Logger.getLogger'在內部調用'Logger'。總是有一個構造函數調用 - 只是不總是在*你的代碼中。 – Blorgbeard

+0

WOW這個在短時間內有很多答案... – Doorknob

回答

0

在你的例子中你必須有不同的用例:返回一個對象的靜態方法和實際的構造函數調用。

靜態方法是一種不需要在對象上調用的方法,在這裏它的內部機制可以實例化對象並將其返回以用於未來使用,在此方法中,調用「新」但除對象可能被配置,或者在返回之前從緩存中檢索。這是這種通話

Logger logger = Logger.getLogger("com.foo"); 

的實際構造函數調用(使用新)是正常的方式來創建新的對象。

1

因爲Logger.getLogger()返回Logger對象。 new Logger()調用也返回Logger的構造函數。這也是一種採用new過,因爲Logger類裏面大概是這樣的:

public class Logger { 
    public static Logger getLogger() { 
     return new Logger("foo", "bar"); 
    } 
} 
0

你不是技術上使用Logger類,但使用的方法。 您在技術上沒有實例化Logger類,也沒有像直接使用Logger logger = new Logger()那樣直接引用它。相反,你正在做的是訪問一個方法來取回返回的實例。很高興看到類定義。然而,你所擁有的更多的可能是類內部的靜態方法。而且這個類很可能是用私有構造函數定義的。這允許在不實例化類的情況下訪問這些方法。你可以在這裏看到一個很好的解釋和這裏的靜態:https://stackoverflow.com/a/1844388/1026459

+0

他正在使用Logger類,只是不直接調用構造函數。 – Blorgbeard

+0

@Blorgbeard - 我應該改述一下。 –

7

在Java中創建一個新對象的唯一方法是使用new [1]。但是,在某些類中,您不允許自己說new,您必須調用一個工廠方法,這可能是靜態的(與您的記錄器示例一樣)或不是。一個類的作者通過使構造函數具有除public以外的訪問權限來設置它。

另請注意,您的示例可能根本不涉及新對象。 Logger函數可能會返回一箇舊對象,而不是一個新對象。

以下首詩奧格登納什似乎依稀相關:

This morning I went to the zoo 
In order to look at the gnu. 
But the old gnu was dead, 
and the new gnu, they said, 
Was too new a new gnu to view. 

[1]除非你涉足低級別的反射,或使用Object.clone()

+0

有新操作符的替代方法:http://stackoverflow.com/questions/95419/what-are-all-the-different-ways-to-create-an-object-in-java – maba

1

例如,某些類可能會阻止您在應用程序中創建多個對象。在這種情況下,您需要調用一些方法來實例化類,如Logger.getLogger()。 getLogger()可能具有這樣的代碼:

if(uniqueInstance == null) { 
    uniqueInstance = new Logger(); 
} 

return uniqueInstance; 

其中uniqueInstance是Logger的一個實例。這是一種稱爲Singleton的設計模式。在這種模式下,你不能實例化類,因爲它的構造函數是私有的。

你不能實例化一個類的其他方法是當類被定義爲靜態的時候。

具有公共構造函數且不是靜態的類需要使用new關鍵字實例化。

0

有些類不能在自身之外實例化(例如Math類,這些類具有非公共構造函數)。在這些類中,有些提供返回類實例的方法(例如InetAddress類)。這些被稱爲工廠方法。它們是返回它們所在類的實例的static方法,因此不需要使用new關鍵字(它在工廠方法內部使用)。例如:

public class A { 
    private A() {} 
    public A createAnA() { return new A(); } 
} 

這裏,createAnA()是工廠方法。

3

在這種情況下,我們正在處理工廠方法,正如我在my comment中所述。

查看Logger

相關的API規範檢索根據名稱參數的值命名記錄器。如果指定的記錄器已經存在,那麼現有的實例將被返回。否則,將創建一個新實例。

默認情況下,日誌記錄器沒有設置的級別,但是從具有設置級別的其最近的祖先繼承它。這是log4j的核心功能之一。

factory method pattern是造物設計圖案,並且,根據維基百科,通常是有用在下列情況下:

工廠模式時,可以使用:

  • 創建的對象排除了重複使用而沒有重複代碼的重複。
  • 創建對象需要訪問不應包含在組合類中的信息或資源。
  • 生成對象的生命週期管理必須集中以確保應用程序內的一致行爲。

這三種適用於這...誰知道什麼樣的工作進入找到正確的記錄?你不是真的有興趣創建一個全新的記錄器,每次你想使用一個...相反,你的焦點主要是這樣 - 使用之一。

知識共享Wiki也有relevant article

工廠方法代替構造函數有時也用於任何的幾個原因:

  • 一些語言(如Java)不允許構造函數具有有用的名稱
  • 某些語言(如Java)不允許構造函數具有不同的名稱(如果要爲兩個構造函數使用相同的方法簽名,這可能是必需的)
  • 允許同樣的實例被在每次需要時再次使用,而不是重新創建(見FlyweightPattern

我覺得第三個選項可能是最適用於此。使用手動創建新的Logger,您無法充分共享它們。使用getLogger外觀可以使其透明。

總而言之,工廠方法的使用通常是爲了使清潔更直接的代碼,而不會暴露你不一定關心的工作。

1

那麼你問的是更多的設計模式相關。 Logger類遵循單例模式。

假設您希望在應用程序中只創建類的單個實例,那麼您可以使構造函數保持私有狀態,並提供一個靜態方法,該方法在第一次調用時創建並存儲類的對象。

公共類SingletonPattern {

 private static SingletonPattern instance; 

    private SingletonPattern(){} 

    public static synchronized SingletonPattern getInstance(){ 
     if (instance == null){ 
      instance = new SingletonPattern(); 
     } 
     return instance; 
    } 
} 

這樣可以限制你的類只進行一次實例化。

相關問題