2014-11-09 117 views
12

Bellow是一個我在Tutorials Points上找到的例子,它是構造函數的一個例子。我得到了他們大部分,但我只是不明白爲什麼你需要一個構造函數的一種方法。構造函數和方法之間的區別

public Puppy(String name){ 
    System.out.println("Passed Name is :" + name); 
} 

我的問題是,什麼阻止你這樣做呢?

public static void Puppy(String name){ 
    System.out.println("Passed Name is: "+name); 
} 

難道這兩個人不會一次做同樣的事情嗎?

下面是完整的程序供參考:

public class Puppy { 
    int puppyAge; 

    public Puppy(String name) { 
     System.out.println("Passed Name is :" + name); 
    } 

    public void setAge(int age) { 
     puppyAge = age; 
    } 

    public int getAge() { 
     System.out.println("Puppy's age is :" + puppyAge); 
     //what does this return do? since the puppyAge is already printed above. 
     return puppyAge; 
    } 

    public static void main(String []args){ 
     Puppy myPuppy = new Puppy("tommy"); 

     myPuppy.setAge(2); 
     myPuppy.getAge(); 

     System.out.println("Variable Value :" + myPuppy.puppyAge); 
    } 
} 
+0

哪種方法做你相信是複製構造的工作?只有構造函數和其他方法執行相同的任務時,其中一個纔是不必要的。然而,在這種情況下,構造函數並沒有完成它應該做的所有事情 - 特別是構造函數應該設置類中所有成員變量的值(並且不設置puppyAge,因此實例處於未定義狀態狀態後立即建設),並沒有使用小狗的名稱來設置變量(所以爲什麼它提供了小狗的名字呢?)。 – Simon 2014-11-09 02:25:40

回答

5

構造函數方法,它們是特殊類型的方法,但是。構造函數是沒有返回類型的方法,並且必須在它們的封閉類之後進行命名。那麼爲什麼我們需要構造函數呢?那麼,我們就可以創建類的實例。當你想創建一個特定類的實例時,你可以通過調用它的構造函數來實現。構造函數爲對象保留內存並返回對新創建對象的引用。

2

構造函數應該是設置對象的地方,因爲方法只是對對象做一些操作。 Java是面向對象的,所以整個語言圍繞着對象旋轉。構造函數也不能返回任何東西,必須和new一起使用才能返回創建的對象的實例,因爲方法可以返回任何東西或根本不返回任何東西。

2

A Constructor就是這樣做的,它在技術上「構造」你創建它的對象是一種特定類型的Method。 A Method用於修改對象,主要是做一個單一的邏輯。請參閱:single responsibility principle

類別/方法應該很簡單,並處理一些精確的信息,例如,如果你想要它的屬性是長度,寬度,高度,體積,面積等等,你的構造函數必須是一個Shape對象:

public Shape (double length, double width, double height, double volume, double area, ect...) { 
    //code here 
} 

(注意這個方法的名稱應該是相同類的名稱,標誌着一個「Constructor`)

這是什麼知道作爲一個code smell,具體如下:參數太多。閱讀起來很困難,不是非常有組織,只是編寫代碼的不好方法。因此,相反,使用方法來設置這些變量:

public void setLength(double length) { 
    //code here 
} 

然後你的構造就只能是:

​​

這只是一個簡單的例子。在許多情況下,您可能需要根據具體情況將參數(或幾個)傳遞給構造函數。

2

對於這個例子,你不需要一個構造函數。這是一個非常糟糕的例子。一個方法也可以工作。

(所有的Java類有一個默認的構造函數,如果你不添加一個,所以你仍然可以調用new Puppy()得到一個實例。)

22

您沒有得到實例的基本概念,這是OOP的基礎。如果你想要一個比喻,我們來談談汽車。

我很確定你知道什麼是汽車;你知道它可以讓你從一個地方移動到另一個地方,它有四個輪子,等等。這是一個概念,你在車庫中的實際車輛是這個概念的實例< =>)。

構造函數的目標是創建一個實例,而不是打印某些文本。沒有構造函數,你將永遠無法調用你的類的非靜態方法。你不能駕駛汽車的概念,你需要先建立一輛汽車。

只要回顧一下這些概念;沒有它,你將無處可去。

3

關於構造函數已經有幾個很好的答案。

小點;你不能擁有一個和你的班級同名的靜態方法。對於構造函數,這個名字是保留

2

當您創建對象的新實例(Puppy doggy = new Puppy("Bobby");)時,將立即調用構造函數。它構造了新的對象。它用名字「Bobby」來構造它。 (小狗出生時名字叫「鮑比」)。假設我們的小狗對它的名字感到不滿意,並且想要將其改爲「史努比」。然後你可以調用方法:doggy.setName("Snoopy");

10

我想你的問題是,爲什麼使用創建的構造......

public Puppy(String name) 

的...,而不是...

public static void Puppy(String name) 

......吧?

如果是這樣,首先您應該知道構造函數是一個特殊方法,該類由您在創建該類的新實例時調用的類所擁有。所以,如果,例如,你有這個類...

public class Clazz { 
    public Clazz (String s) { 
     System.out.println(s); 
    } 
} 

...,然後當你創建這個類等構成的新實例...

Clazz c = new Clazz("Hello World"); 

...中,構造函數將被調用並且該方法將被執行。 (在這個例子中,它會在屏幕上打印「Hello World」。)

也就是說,您可以看到構造函數是一個方法,但是它是在類實例化時調用的特殊方法。所以,關於你的問題,構造函數是正確的,而不是常規的方法頭的原因是向編譯器指出它是一個構造函數而不是常規方法。如果您編寫public void Clazz()而不是public Clazz(),那麼編譯器將無法識別您的構造函數,並會認爲這只是一個常規方法。

請注意,構造函數從不返回任何內容,因此不需要使用關鍵字。而且,使構造函數成爲靜態是沒有意義的,因爲在實例化新對象時會調用構造函數。

+1

'構造函數從不返回任何東西,所以不需要使用void關鍵字'這是一種奇怪的思考方式。我一直認爲相反:他們返回一個他們特定類型的對象。在'public Clazz()'中,我會考慮'Clazz'的返回類型,而不是「方法」名稱。 – nbrooks 2014-11-09 08:35:48

+0

@nbrooks你說的話有道理。但在java文檔中寫道,構造函數**不具有返回類型。但現在你已經說過了,我想兩種方式都是正確的 – felipeek 2014-11-09 16:35:32

+0

我認爲文檔說你不使用'return'關鍵字,而不是沒有返回類型。我們知道它會返回一些東西,否則你不能像這樣使用方法調用來鏈接構造函數:'new String(「Hello World」)。substring(3)'。 – nbrooks 2014-11-09 21:32:55

2

構造函數是類型的方法。具體來說,它在您實例化該類的對象時被調用。因此,在你的例子,如果你寫:

Puppy pup = new Puppy("Rover"); 

您創建一個名爲pup的對象,實例化對象,它允許您使用它。通過實例化它,您可以調用指定的構造函數,在這種情況下:public Puppy(String name)其中設置打印到"Rover",但這不是一個真正的構造函數的好用處。更有意義的是將String puppyName;作爲字段變量,並且this.puppyName = namep.puppyName設置爲等於構造函數中傳遞的值。

5

換句話說在Java Spec for Constructors

  • 構造函數不返回任何,因此他們沒有返回類型。

    在所有其他方面,構造函數聲明看起來就像沒有結果的方法聲明(§8.4.5)。

  • 您無法重寫構造函數。

    構造函數聲明不是成員。他們從來不會被遺傳,因此不會被隱藏或壓倒。

  • 他們不能直接訪問實例變量,而必須使用thissuper委託給類變量。

    在構造函數體中一個明確的構造函數調用語句可能不是指這個類或任何父類的任何實例變量或實例方法或內部類,或使用本或超在任何表情;否則,會發生編譯時錯誤。

+0

我想你看的最後一個錯誤:你可以在構造函數訪問任何類或實例變量,而是調用'超(...)'或'這個(...)'不能訪問實例成員或類成員。 – 2014-11-09 05:55:27

2

我真的喜歡閱讀一本關於面向對象的概念,在這種情況下的Java,比這裏閱讀完所有的(好)的答案。你可能會得到很多答案,因爲這個問題相當受歡迎,但答案不會包含所有必要的細節。

但有一兩件事我想在短期提到:

public int getAge() { 
    System.out.println("Puppy's age is :" + puppyAge); 
    //what does this return do? since the puppyAge is already printed above. 
    return puppyAge; 
} 

的方法可以用某種答案的回報。 那麼這種方法做什麼?它返回值,保存在變量中,名稱爲puppyAge, ,它是一個整數。 因此,如果您調用方法myPuppy.getAge(),則會處理此方法中的所有內容(實際上也是打印輸出), 將被處理,然後返回。在你的情況下,你不會在任何地方保存返回值。 但你想做的'正常'事情是通過方法 訪問小狗的年齡,並實際上做一些事情,比如計算你所有的小狗和東西的平均年齡。 當然,你可以從課外訪問變量,因爲你沒有設置可見性修飾符,比如public,private,protected。

public class Puppy { 
    int puppyAge; 

實際上沒有公共修飾符也有含義,但這與現在不相關。 所以,你想要做的是,例如將其設置爲私有:

private int age; 

,並通過方法來訪問它像getAge(),並用它做什麼,如:

int allAgesummed = puppy1.getAge() + puppy2.getAge() + 
puppy3.getAge(); 

最後,如果你只是要打印出年齡在控制檯上,你的方法只能做到這些一兩件事,應該相應地命名,如:

public void printAgeToConsole(){ 
    System.out.println("Age: " + age); 
} 

void表示此方法執行某些操作,但不返回任何內容。

2

構造是 公共類(){ 定義需要在全班 方法使用的就是去下構造 公共無效的方法名(){} U可以改變空隙,美想要的變量類型變量方法返回特定的類型。

2

你的第一個例子是一個公共的構造函數,當你實際創建一個Puppy時被調用。通常情況下,構造函數保存名稱,而不是顯示它,並把它扔了,所以你可以回到它以後,例如:

public class Puppy{ 
    private String puppyName; 

    public Puppy(String name){ 
     puppyName = name; 
    } 
    public void bark(){ 
     System.out.println(puppyName + ": woof!"); 
    } 
    ... 
} 
... 
public static void main(){ 
    Puppy Spot = new Puppy("Spot"); // here, the constructor is called, which saves the name 
            // "Spot" into the variable Spot.puppyName. 

    Puppy Fido = new Puppy("Fido"); // on this line, the constructor is called again, but this time, the string 
            // "Fido" is saved into Fido.puppyName. 

    Spot.bark();     // output: "Spot: woof!" 
} 

我認爲一個構造函數的方法是「收益」一小狗對象,這就是爲什麼它沒有返回類型。與小狗的名字不同,被聲明爲靜態的方法和變量並不「特別」屬於任何對象,而是在該類的所有成員之間共享。

public class Puppy{ 
    ... 
    private static String latinName; 
    public static void setLatinName(String newLatinName){ 
     latinName = newLatinName; 
    } 
    public static void printLatinName(){ 
     System.out.println("I am a " + latinName + "."); 
    } 
}; 
... 
static void main(){ 
    Puppy Spot("Spot"); 
    Puppy Fido("Spot"); 
    Spot.setLatinName("Canis Lupus"); 
    Fido.setLatinName("Canis Lupus Familiaris"); 

    Spot.printLatinName(); // output: "I am a Canus Lupus Familiaris." 
    // even though we used the Fido object to change the latinName string, 
    // the output of Spot's non-static method still reflects the change because 
    // latinName is a static field: there is only one String latinName 
    // shared among all members of the class. 
} 

雖然你可以使用小狗對象調用靜態方法(如果小狗是一個多態犬可能是特別有用),逆是不是也是如此!

public class Puppy{ 
    ... 
    public static void bark(){ 
     System.out.println(puppyName + ": woof!"); // this will not compile! 
    } 
} 

在靜態函數的上下文中引用非靜態數據成員是無效的(也沒有意義)!靜態函數與靜態變量相似:在所有成員對象中只有一個函數副本共享。這意味着你可以給Puppy打電話。setLatinName()(而不是Spot.setLatinName())。你不需要使用特定的Puppy對象來調用一個靜態函數:一個靜態函數被保證不依賴於任何非靜態成員變量(因爲它沒有)。調用Puppy.bark()沒有意義,因爲類「Puppy」沒有puppyName;每個Puppy都有自己的puppyName。

我希望這會有所幫助。面向對象的編程非常強大,而且理解好基礎很重要!祝你好運。

相關問題