本文關鍵字:對象、初始化、實例化、構造器、構造方法java
明確了類與對象的關係後,咱們知道:類只是一個定義的結構,用來表述咱們想要描述的事物,即具有哪些屬性(成員變量),能夠產生哪些行爲(方法)。那麼具體行爲的發生,也就是方法的調用要靠對象來完成,同時屬性值也要附着在對象上纔有意義。建立對象的過程被叫作類的實例化,或者稱爲對象的初始化,在這個過程當中須要使用的就是new關鍵字和類的構造器。
對於相關概念還不清楚的同窗請進傳送門:Java中的基本操做單元 - 類和對象運維
沒錯,他們都是同一個意思。ide
構造器自己更像一種方法,所以定義的格式與方法相似,能夠區別着進行記憶。構造器一樣被定義在class的大括號內,構造器的定義格式以下:函數
public class className{ // 構造器定義開始 [權限修飾符] 類名(參數列表){ // 代碼部分 } // 構造器定義結束 }
從以上的結構咱們看到,構造器的聲明格式與方法相似:工具
那麼,在這個構造方法當中咱們都應該寫些什麼呢?仍是從構造器的做用入手,既然他的做用是初始化一個對象,那麼對象在初始化時最須要作的就是對屬性賦值,因此若是有須要咱們會在調用時傳入某些屬性的初始值,或者在對象初始化時執行某些代碼,幫助咱們判斷對象初始化的狀態。學習
public class Student{ public Student(){ System.out.println("學生對象初始化成功"); // 其餘代碼 } }
public class Test{ public static void main(String[] args){ Student student = new Student(); // 執行效果 -> 輸出:學生對象初始化成功 } }
對於建立對象時爲屬性賦值的用法將在構造器的重載中演示。測試
在剛剛開始學習面向對象部分時,可能都會存在一個疑問,以前定義的class都沒有定義構造器呀,不是同樣能夠經過new來建立實例嗎?這是由於當一個類被定義後,若是沒有手動的建立任何的構造方法,會默認提供一個空的構造器,供初始化使用,這個過程是編譯時完成的。this
public class Person{ }
咱們對Person類進行編譯,獲得Person.class文件,而後咱們對class文件進行反編譯,就能夠看到已經出現了一個空的構造器:
Java程序在執行時,加載的都是.class文件,而且所生成的.class文件與咱們定義的.java文件通常都是存在差別的。因此這就可以解釋,爲何明明咱們在.java文件中沒有定義構造器,可是在建立對象時卻可使用new調用到。
隱式構造器還有一個特色,就是若是咱們已經手動建立了一個無參的構造器,或者一個有參的構造器,那麼在編譯時就不會生成無參構造器了。code
public class Person{ public Person(String name){ System.out.println(name); } }
此時,因爲咱們已經手動指定了一個構造器了,因此在編譯時就不會再產生默認的無參構造器了,只會有本身手動定義的構造器:
那麼,你們應該也注意到了一個問題,既然用new建立對象時是調用的構造器,那麼如今咱們本身定義了一個有參數的構造器,那麼就會使得咱們最常使用的new Person()這種實例化的代碼報錯,由於此時類中已經沒有無參構造器可供調用了,也能夠認爲無參的構造器被覆蓋了,必需要傳入一個參數才能初始化對象。對象
public class Test{ public static void main(String[] args){ Person person = new Person(); // 編譯不經過,已經沒法調用無參構造器來初始化對象 } }
那麼若是咱們仍是想用這個無參構造器來建立對象該怎麼辦呢?沒錯,手動聲明一下就行了,裏面不須要寫任何內容:
public class Person{ // 無參構造器 public Person(){} // 有參構造器,能夠接收一個參數 public Person(String name){ System.out.println(name); } }
咱們來看一下效果,很明顯,將會同時存在兩個構造器,咱們在使用new進行對象初始化的時候能夠根據須要來使用。`
public class Test{ public static void main(String[] args){ Person person1 = new Person(); // 編譯經過,執行後person1被成功實例化,無輸出 Person person2 = new Person("小明"); // 編譯經過,執行後person2被成功實例化,輸出:小明 } }
從上面的例子咱們已經能夠看到,一個類結構中能夠存在多個構造器,用於在有不一樣須要時被調用。並且因爲構造器自己的主要做用是用於爲類的屬性賦初始值,因此在構造器中咱們會指定一些參數,用於被調用時傳入,爲當前類的屬性賦值。
public class Person{ // 無參構造器 public Person(){} // 兩參構造器,能夠給name和age屬性賦值 public Person(String name,int age){ this.name = name; this.age = age; } // 三參構造器,能夠給name、age和job屬性賦值 public Person(String name,int age,String job){ this.name = name; this.age = age; this.job = job; } public String name; public int age; public String job; }
在上面的代碼中咱們能夠看到有三個構造器,名稱相同,只有參數列表不一樣,這種關係被稱爲重載,在方法中也有相似的概念。能夠看到構造器中存在部分代碼,且都是賦值語句。
this能夠指代當前對象,<font color="red">使用this能夠調用出直接在類下定義的成員(變量和方法)</font>,其中一個最主要的做用就是能夠區分同名的變量。咱們在進行變量命名時,一直強調見名知意,那麼問題就來了:在類中定義的成員變量名稱已經肯定了,而構造器中傳入的參數就是爲了給這些屬性賦值的,那麼參數的名稱是否是應該和類成員變量同樣才更能表達意思呢?若是這樣的話就形成了參數列表中的變量名稱與類成員變量的名稱同名,這時就能夠經過this來區分。
明確了this的用法,咱們再來看構造器中的內容就很好理解了,將傳入的參數賦值給當前對象的類成員變量,具體的調用過程咱們看下面的例子。
src └──edu └──sandtower └──bean │ Person.java └──test │ Test.java
以上爲實體類與測試類所在的目錄結構,Person實體類所在包:edu.sandtower.bean,Test測試類所在包:edu.sandtower.test,則代碼以下:
package edu.sandtower.bean; public class Person{ // 無參構造器 public Person(){} // 三參構造器,能夠給name、age和job屬性賦值 public Person(String name,int age,String job){ this.name = name; this.age = age; this.job = job; } public String name; public int age; public String job; }
package edu.sandtower.test; // 導包操做:指明須要使用的Person類的所在位置 import edu.sandtower.bean.Person; public class Test{ public static void main(String[] args){ Person person1 = new Person(); // person1被成功實例化,各屬性無初始值,能夠手動賦值 person1.name = "小張"; person1.age = 26; person1.job = "Linux運維工程師"; Person person2 = new Person("小李",25,"Java開發工程師"); // person2被成功實例化,並具備以下初始值 // name:小李 // age:25 // job:Java開發工程師 // 輸出進行驗證 System.out.println("name:" + person2.name); System.out.println("age:" + person2.age); System.out.println("job:" + person2.job); } }
在進行對象的初始化時,能夠根據須要取得一個空的對象(如:person1)後手動賦值,也能夠經過有參構造器直接對屬性賦值(如:person2),避免逐一賦值的麻煩。