類:描述生活中的一類事物,是一類事物所具備的共性內容。好比人類,動物類,車類。
對象:基於這個類的實體(實例),好比人類中的某一個具體的人,張三就是一個具體的對象,一個具體實例。他有本身的屬性(年齡,性別,身高,地址等等),行爲(吃飯,睡覺,學習等等),經過實例就能夠調用行爲功能。java
注意:類是一些相關屬性與行爲的集合,是對象的抽象描述,對象是類的實例。先要使用類來描述事物,纔可使用類來建立對象。函數
對於人這個事物而言,通常人在出生以後就會有名字和年齡,那麼這個事物一旦被建立就會有本身特定的屬性。
建立一個對象的時候,若是須要建立好以後,就必須擁有一些屬於本身自己特有的數據,而不是後面經過其餘方式去修改,那麼也就是說在建立對象的過程當中,就應該把這些數據賦值完成。學習
構造函數就是使用關鍵字new建立對象時,JVM會自動調用的函數,用來對對象成員變量進行初始化。測試
能夠說沒有構造函數就沒有對象,構造函數是建立對象的。this
①javac命令,啓動編譯器,檢查基本語法錯誤。而後編譯源程序生成可被虛擬機執行的字節碼文件(也就是class文件)spa
②java命令,啓動JVM,加載class文件到方法區,找到程序入口(main方法),main方法進棧。
③ 經過new關鍵字,在堆內存開闢內存空間,對對象所在類的成員變量進行默認初始化,而後調用構造方法(無參構造調用無參,有參構造調有參構造)
④ 執行構造函數的隱式三步(super對父類進行初始化、對對象成員變量顯示初始化、執行構造代碼塊)
⑤ 執行構造函數中的其它代碼,其它代碼執行完畢,構造函數出棧,對象建立完畢。
⑥ 把對象的內存地址值返回給棧內存開闢的引用變量空間。3d
4.1.時間不一樣:
①構造函數在對象建立過程當中執行,當對象建立完畢,構造函數就結束了。②通常函數是在對象建立完畢以後,經過對象的引用(對象堆內存地址值)來調用,何時使用,何時調用。
4.2.調用次數不一樣
①構造函數只要在new對象的時候,會被調用,一旦對象建立完成,咱們不能手動去調用構造函數。②通常函數能夠經過對象隨意的調用,沒有次數限制。
4.3.互相調用問題
①在構造函數中能夠調用通常的函數,可是通常函數不能調用構造函數
4.4.調用方式不一樣
①構造函數是在建立對象時,由JVM自動調用②通常函數是在對象建立完畢,經過對象調用
①構造函數是用來建立對象的,它不須要書寫返回值
②構造函數的名字必須和當前類名一致。
③參數列表,能夠和通常函數的參數列表同樣。(構造函數是以重載方式存在的)對象
默認構造函數:當咱們寫一個類的時候,在這個類中不寫任何的構造函數,那麼在使用javac編譯java源代碼以後,生成class文件中,會自動添加一個沒有參數的構造函數。把這個構造函數稱爲默認的構造函數。blog
注意:若是本身沒有寫無參構造,那麼編譯器會在class文件自動添加一個無參構造,若是本身寫了構造函數(不管是有參仍是無參構造),那麼編譯器不會再class文件添加默認的構造函數。遞歸
因爲一個類中能夠產生多個對象,那麼咱們就要知道類中的構造函數究竟是哪一個對象所調用的,咱們同時也要知道當前構造函數是給堆內存中哪一個地址中的哪一個對象的成員初始化值,因此在當前構造函數進入棧內存的時候,會在棧內存中的構造函數中生成一個隱式的this引用變量,來記錄當前這個構造函數是被哪個對象調用。
1.1. 同一類中構造方法之間相互調用
通常方法調用:方法名(參數列表)。構造方法調用: this(參數列表), 表示調用本類的其它構造。
1.2. 不能相互嵌套調用,不然會是死遞歸。
1.3. this語句必須在構造的第一行
當有this(參數列表)的時候,就沒有隱式super()了,由於初始化只能有一個,並且他倆不能公用,由於都須要放在語句的第一行,
父類的構造只要子類訪問,完成父類的初始化就行(無論訪問的是父類的有參仍是無參構造)。
1.4. 記錄調用函數的對象地址值
this和對象有關,與類無關,誰調用this保存那個對象的地址值。
1.5. 區分局部變量和成員變量
只要是對象調用(不論是間接仍是直接),就有隱式this,來記錄對象的地址值。只有保存了地址值,才能賦值調用等其餘操做。靜態方法中沒有this,this是和對象有關的,而靜態方法是和類有關的。
2..1. 構造函數之間不能相互嵌套使用,這樣就致使無限制調用構造函數,致使死遞歸的問題。
2.2. this調用構造函數,必須放在構造函數的第一句。
咱們經過this調用其餘構造函數的目的就是但願經過其餘的構造函數完成初始化動做,所以要求其餘構造函數的初始化必須在本構造函數以前先完成初始化。
this:這個的意思,誰調用this就記錄該對象的堆內存地址值。
注意:不論是構造函數仍是通常函數,由於都要使用對象,因此只要經過對象調用,那麼在這個函數中都有一個this引用變量存在,記錄當前調用這個函數的對象堆內存地址值。
package cn.jason01; /** * 這是演示構造函數和this關鍵字的用法 * @author Jason */ public class Student04 { private static String name; private static int age; private int number; public Student04() { // recursive constructor invocation Student03 // 遞歸結構調用Student03,那麼會是死遞歸,調用只能調用有參的 // this(); this("林青霞", 27); System.out.println("⑤ 無參構造...this的地址值: " + this); show(); this.show(); } // 構造兩個參數 public Student04(String name, int age) { super(); this.name = name; this.age = age; System.out.println("① 有兩個參數構造...this的地址值:" + this); System.out.println("② 隱含this調用成員變量: " + name + " " + age); System.out.println("③ this調用成員變量: " + this.name + " " + this.age); System.out.println("④ 類名調成員變量: " + Student04.name + " " + Student04.age); } // 構造三個參數 public Student04(String name, int age, int number) { this(name, age); this.name = name; this.age = age; this.number = number; System.out.println("有三個參數構造...this的地址值:" + this); System.out.println("this調用成員變量 :" + name + " " + age + " " + number); } public void show() { System.out.println("⑥ show方法...this的地址值:" + this); } }
Student04Test測試類
package cn.jason01; /** * 這是測試構造函數和this關鍵字的類 * @author Jason * */ public class Student04Test { public static void main(String[] args) { System.out.println(".................構造函數以及this關鍵字的用法.................\n"); System.out.println("...................建立對象,使用無參構造...................."); Student04 s = new Student04(); System.out.println("..................無參構造完畢,建立對象完畢...................\n"); System.out.println("...................建立對象,使用有參構造...................."); Student04 s1 = new Student04("林青霞", 27, 123456); System.out.println("..................有參構造完畢,建立對象完畢...................\n"); } }
輸出結果:
.....................................構造函數以及this關鍵字的用法..................................
.........................................建立對象,使用無參構造.........................................
① 有兩個參數構造...this的地址值:cn.jason01.Student04@22aed3a5
② 隱含this調用成員變量: 林青霞 27
③ this調用成員變量: 林青霞 27
④ 類名調成員變量: 林青霞 27
⑤ 無參構造...this的地址值: cn.jason01.Student04@22aed3a5
⑥ show方法...this的地址值:cn.jason01.Student04@22aed3a5
⑥ show方法...this的地址值:cn.jason01.Student04@22aed3a5
......................................無參構造完畢,建立對象完畢.......................................
.........................................建立對象,使用有參構造.........................................
① 有兩個參數構造...this的地址值:cn.jason01.Student04@3c9076d
② 隱含this調用成員變量: 林青霞 27
③ this調用成員變量: 林青霞 27
④ 類名調成員變量: 林青霞 27
有三個參數構造...this的地址值:cn.jason01.Student04@3c9076d
this調用成員變量 :林青霞 27 123456
......................................有參構造完畢,建立對象完畢......................................
注意事項:
靜態變量在靜態區開闢空間存儲數據,先給靜態成員變量默認初始化,當全部的靜態成員變量默認初始化完畢,JVM又會從新開始給每個靜態變量從新顯示初始化(賦值初始化),這時類才加載完成。
內存圖中凡是箭頭指向靜態區的表示:先在堆內存找,沒有就在方法區找所在的類,而後在靜態區找成員變量,這裏並無引用指向。只有關鍵字new出來的對象纔有地址引用。
3.內存圖詳解
① java命令啓動JVM,JVM先加載mian函數所在的類,加載Student04Test.class字節碼文件到方法區,靜態區加載到靜態區,非靜態加載到非靜態區。
②當Student04Test.class字節碼文件加載完成時,程序向下執行,從方法區中把mian方法加載到棧內存,而後向下遇到Student04這個類,JVM先在方法區中找,沒有就加載Student04.class字節碼文件到方法區。
③④由於Student04.class中有靜態成員變量,靜態成員變量和成員方法、靜態代碼塊都加載到靜態區中,而後纔對靜態成員變量開闢空間,進行默認初始化。當全部靜態成員變量默認初始化完成後,JVM又從新對靜態成員變量進行顯示初始化。當顯示初始化完成後,全部的類文件才加載完成。
⑤建立Student04的對象,建立對象先執行右邊,先在堆內存開闢空間,好比十六進制的地址值是0x12,而後對Student04的成員變量進行默認初始化,即int number=0。
⑥而後JVM自動調取Student04相對應的構造函數,那麼Student04的無參構造進棧,由於有this("林青霞",27),因此就沒有super,this和super不能共存在一個方法中。
⑦那麼經過this("林青霞",27)訪問Student04的帶參構造,這時Student04的帶參構造也有隱式this記錄了當前對象的地址值,由於是this("林青霞",27)訪問Student04的帶參構造,因此間接把地址值0x12給了Student04的帶參構造。把林青霞,27傳參給了有參構造的局部變量name和age,由於成員變量name和age是靜態static修飾,因此在堆內存中沒有找到,就會去方法區中找,而且修改其值。當完成這些以後,Student04的有參構造執行完畢,出棧,就從棧內存消失。
⑧而後回到Student04的無參構造執行下一行代碼show方法,那麼show方法從方法區中加載到棧內存,隱式this機路地址值0x12,而且指向堆內存。
⑨show執行完畢,出棧,從棧內存消失。
⑩student04的無參也執行完畢,出棧,從內存中消失。
⑪這時student04的構造函數執行完畢,Student04的對象建立完畢。執行建立對象的左邊,在main方法中給Student04開闢空間,空間名稱爲引用變量s,在吧地址值返回給s。
⑫main方法出棧內存,完成。
1.從上圖結果能夠看出,只要是對象調用的函數(方法)就存在隱式的this,用來記錄哪一個對象的地址值。
2.當函數(方法)中存在局部變量和成員變量同名時,使用this就指的是成員變量,不然根據就近原則,局部變量在棧內存開闢空間,把傳過來的值又覆蓋本身的值,成員變量根本就沒有賦值,因此沒意義。