1. 程式人生 > >建構函式用法及this關鍵字的記憶體圖解

建構函式用法及this關鍵字的記憶體圖解

一.類和物件的概述

類:描述生活中的一類事物,是一類事物所具有的共性內容。比如人類,動物類,車類。
物件:基於這個類的實體(例項),比如人類中的某一個具體的人,張三就是一個具體的物件,一個具體例項。他有自己的屬性(年齡,性別,身高,地址等等),行為(吃飯,睡覺,學習等等),通過例項就可以呼叫行為功能。

注意:類是一些相關屬性與行為的集合,是物件的抽象描述,物件是類的例項。先要使用類來描述事物,才可以使用類來建立物件。

二.建構函式

1.建構函式的緣由

對於人這個事物而言,一般人在出生之後就會有名字和年齡,那麼這個事物一旦被建立就會有自己特定的屬性。
建立一個物件的時候,如果需要建立好之後,就必須擁有一些屬於自己本身特有的資料,而不是後面通過其他方式去修改,那麼也就是說在建立物件的過程中,就應該把這些資料賦值完成。

2.建構函式作用

建構函式就是使用關鍵字new建立物件時,JVM會自動呼叫的函式,用來對物件成員變數進行初始化。

可以說沒有建構函式就沒有物件,建構函式是建立物件的。

3.建構函式執行時機

①javac命令,啟動編譯器,檢查基本語法錯誤。然後編譯源程式生成可被虛擬機器執行的位元組碼檔案(也就是class檔案)

②java命令,啟動JVM,載入class檔案到方法區,找到程式入口(main方法),main方法進棧。
③ 通過new關鍵字,在堆記憶體開闢記憶體空間,對物件所在類的成員變數進行預設初始化,然後呼叫構造方法(無參構造呼叫無參,有參構造調有參構造)
④ 執行建構函式的隱式三步(super對父類進行初始化、對物件成員變數顯示初始化、執行構造程式碼塊)
⑤ 執行建構函式中的其它程式碼,其它程式碼執行完畢,構造函數出棧,物件建立完畢。
⑥ 把物件的記憶體地址值返回給棧記憶體開闢的引用變數空間。

4.建構函式與一般函式的區別:

4.1.時間不同:
①建構函式在物件建立過程中執行,當物件建立完畢,建構函式就結束了。
②一般函式是在物件建立完畢之後,通過物件的引用(物件堆記憶體地址值)來呼叫,什麼時候使用,什麼時候呼叫。
4.2.呼叫次數不同
①建構函式只要在new物件的時候,會被呼叫,一旦物件建立完成,我們不能手動去呼叫建構函式。
②一般函式可以通過物件隨意的呼叫,沒有次數限制。
4.3.互相呼叫問題
①在建構函式中可以呼叫一般的函式,但是一般函式不能呼叫建構函式
4.4.呼叫方式不同
①建構函式是在建立物件時,由JVM自動呼叫
②一般函式是在物件建立完畢,通過物件呼叫

5.建構函式注意事項

①建構函式是用來建立物件的,它不需要書寫返回值
②建構函式的名字必須和當前類名一致。
③引數列表,可以和一般函式的引數列表一樣。(建構函式是以過載方式存在的)

預設建構函式:當我們寫一個類的時候,在這個類中不寫任何的建構函式,那麼在使用javac編譯java原始碼之後,生成class檔案中,會自動新增一個沒有引數的建構函式。把這個建構函式稱為預設的建構函式。

注意:如果自己沒有寫無參構造,那麼編譯器會在class檔案自動新增一個無參構造,如果自己寫了建構函式(無論是有參還是無參構造),那麼編譯器不會再class檔案新增預設的建構函式。

三.this關鍵字原理

由於一個類中可以產生多個物件,那麼我們就要知道類中的建構函式到底是哪個物件所呼叫的,我們同時也要知道當前建構函式是給堆記憶體中哪個地址中的哪個物件的成員初始化值,所以在當前建構函式進入棧記憶體的時候,會在棧記憶體中的建構函式中生成一個隱式的this引用變數,來記錄當前這個建構函式是被哪一個物件呼叫。

1.this關鍵字的作用

1.1. 同一類中構造方法之間相互呼叫

一般方法呼叫:方法名(引數列表)。
構造方法呼叫:this(引數列表),表示呼叫本類的其它構造

1.2. 不能相互巢狀呼叫,否則會是死遞迴。

1.3. this語句必須在構造的第一行

當有this(引數列表)的時候,就沒有隱式super()了,因為初始化只能有一個,而且他倆不能公用,因為都需要放在語句的第一行, 父類的構造只要子類訪問,完成父類的初始化就行(不管訪問的是父類的有參還是無參構造)。

1.4. 記錄呼叫函式的物件地址值

this和物件有關,與類無關,誰呼叫this儲存那個物件的地址值。

1.5. 區分區域性變數和成員變數

只要是物件呼叫(不管是間接還是直接),就有隱式this,來記錄物件的地址值。只有儲存了地址值,才能賦值呼叫等其他操作。
靜態方法中沒有this,this是和物件有關的,而靜態方法是和類有關的。

2.使用this呼叫建構函式時候注意問題

2..1. 建構函式之間不能相互巢狀使用,這樣就導致無限制呼叫建構函式,導致死遞迴的問題。

2.2. this呼叫建構函式,必須放在建構函式的第一句。

我們通過this呼叫其他建構函式的目的就是希望通過其他的建構函式完成初始化動作,因此要求其他建構函式的初始化必須在本建構函式之前先完成初始化。
this:這個的意思,誰呼叫this就記錄該物件的堆記憶體地址值。


注意:不管是建構函式還是一般函式,因為都要使用物件,所以只要通過物件呼叫,那麼在這個函式中都有一個this引用變數存在,記錄當前呼叫這個函式的物件堆記憶體地址值。

四.案例程式碼

1.Student04類

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的地址值:[email protected]
② 隱含this呼叫成員變數: 林青霞 27
③ this呼叫成員變數: 林青霞 27
④ 類名調成員變數: 林青霞 27
⑤ 無參構造...this的地址值: [email protected]
⑥ show方法...this的地址值:[email protected]
⑥ show方法...this的地址值:[email protected]
......................................無參構造完畢,建立物件完畢.......................................

.........................................建立物件,使用有參構造.........................................
① 有兩個引數構造...this的地址值:[email protected]
② 隱含this呼叫成員變數: 林青霞 27
③ this呼叫成員變數: 林青霞 27
④ 類名調成員變數: 林青霞 27
有三個引數構造...this的地址值:[email protected]
this呼叫成員變數 :林青霞 27 123456
......................................有參構造完畢,建立物件完畢......................................

2.記憶體圖解





注意事項:

靜態變數在靜態區開闢空間儲存資料,先給靜態成員變數預設初始化,當所有的靜態成員變數預設初始化完畢,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方法出棧記憶體,完成。

4.圖解歸納

1.從上圖結果可以看出,只要是物件呼叫的函式(方法)就存在隱式的this,用來記錄哪個物件的地址值。 2.當函式(方法)中存在區域性變數和成員變數同名時,使用this就指的是成員變數,否則根據就近原則,區域性變數在棧記憶體開闢空間,把傳過來的值又覆蓋自己的值,成員變數根本就沒有賦值,所以沒意義。

相關推薦

建構函式用法this關鍵字記憶體圖解

一.類和物件的概述 類:描述生活中的一類事物,是一類事物所具有的共性內容。比如人類,動物類,車類。 物件:基於這個類的實體(例項),比如人類中的某一個具體的人,張三就是一個具體的物件,一個具體例項。

c#建構函式中的this和base

首先要明確: this指向的本例項的建構函式,base指向的時基類的建構函式。 再執行順序上,a、this表明,在執行本建構函式之前,先執行this指向本例項的建構函式,再執行本函式。          

【explicit關鍵字建構函式前面出現的關鍵字

百度explicit,他會這樣說:表示這個函式不能被隱式轉換。但我還是不得它的真意。 但是,我們可以看個例子就明白了它的用法和它所防止出現的錯誤。 1 class Test1 2 { 3 public: 4 Test1(int

C++有元函式用法程式碼演示

有元函式有三種用法: A:有元函式是普通函式 B:有元函式為類中的成員函式 C:有元類 下面一一介紹。 A:有元函式是普通函式 #include "stdafx.h" #include <stdio.h>  #include <iostream> 

深入java (類)建構函式和物件建立的記憶體分配

之前的文章總結了java一些較為常用的關鍵字,現在我們要進入到類裡面,總結類的特徵(其中包括了記憶體和建構函式,gc垃圾回收),java中類的繼承和初始化順序(會涉及到ClassLoader),java多型的深入,java抽象類、介面的深入理解和例子。今天從類開

matlab 中 mvnrnd 函式用法舉例

使用matlab來實現: mu = [2 3]; SIGMA = [1 0; 0 2]; r = mvnrnd(mu,SIGMA,100); plot(r(:,1),r(:,2),'r+'); hold on; mu = [7 8]; SIGMA = [ 1 0; 0 2]; r2 = mvnrnd(mu,S

TP框架的簡稱函式用法意義

cookie  /** * Cookie 設定、獲取、刪除 * @param string $name cookie名稱 * @param mixed $value cookie值 * @param mixed $options cookie引數 * @return m

Pandas.cut函式用法原始碼

Python資料分析博文彙總資料分組:根據資料分析物件的特徵,按照一定的數值指標,把資料分析物件劃分為不同的區間部分來進行研究,以揭示其內在的聯絡和規律性。函式用法:cut(series, bins, right=True, labels=NULL), right=True表

python學習番外篇之print輸出函式用法原理總結

print輸出函式用法及原理總結:        在python2.x中,print作為關鍵字使用,輸出用print語句輸出,例如,x=5 ; print x ,但在python3.x中,print則成為了一個函式,輸出用print()函式輸出,例如:x=5 ; print(

strcpy,strncpy,memcpy,memmove,memset函式用法實現

轉自:http://blog.csdn.net/piaojun_pj/article/details/5945926一.函式介紹:1、memcpy函式原型:extern void *memcpy(void *dest, const void *src, size_t coun

Numpy.random.randint()函式用法原始碼

Python資料分析博文彙總隨機抽樣:隨機從資料中,按照一定的行數或者比例抽取資料函式用法:numpy.random.randint(start, end, num)import numpy; from pandas import read_csv; import panda

js物件建構函式用法

如何寫一個js物件建構函式,首先得明白prototype和new這兩個是什麼意思,做啥的。prototype 屬性使你有能力向物件新增屬性和方法;而new是建立object + this指向object + __proto__指向,具體的解釋可以點開網頁看。 &l

Java初學之this關鍵字原理圖解

說起this關鍵字大家應該都不陌生 我們先來回顧一下this關鍵字。 1.this關鍵字主要有三個應用: (1)this呼叫本類中的屬性,也就是類中的成員變數; (2)this呼叫本類中的其他方法; (3)this呼叫本類中的其他構造方法,呼叫時要放在構造方法的首行。

C# base this 關鍵字在什麼時候使用及其用法,暨使用base this操作建構函式方法

1、首先我有這樣一個需求: public class Class1 { public Class1(Stream stream); } 我想拿到上述程式碼中的Stream,上述程式碼又沒有Stream這個屬性或者GetStream()這個方法,然後上述

Java中this、static關鍵字記憶體圖解

  Java中的關鍵字有很多,abstract  default  goto*  null  switch  boolean  do  if  package  nchronzed  break&nb

java 筆記 this關鍵字建構函式

public String toString() { return "Emp [empno=" + empno + ", ename=" + ename + ", job=" + job + ", sal=" + sal + "]"; } public Em

Java第七天學習筆記~建構函式this關鍵字,static關鍵字

建構函式 構建創造物件時呼叫的函式。 作用:可以給物件初始化,建立物件都必須要通過建構函式初始化 一般函式和建構函式區別? 1,建構函式:物件建立時就會呼叫與之對應的建構函式,物件進行初始化       一般函式:物件建立後需要函式功能時才呼叫

Java學習筆記02--成員變數和區域性變數、建構函式、構造程式碼塊、this關鍵字、static關鍵字、靜態函式

成員變數和區域性變數 自定義的位置區別: 成員變數是定義在方法之外,類之內的變數。 區域性變數是宣告在方法之內的變數。 作用上的區別: 成員變數的作用描述一類事物的屬性。 區域性變數的作用是提供一個變數給方法內部使用的。 生命週期的區別;

Java學習9:super(隱式引數)關鍵字記憶體分析詳解用法

super關鍵字,是一個隱式引數(另一個隱式引數是this)。 注:super關鍵字和this關鍵字極為類似,學習時可參考this關鍵字用法。this(隱式引數)關鍵字記憶體分析詳解及用法 1.概述 super是直接父類的引用(this是當前物件的引用

2017.06.06-日記-面向對象-this關鍵字JAVA源文件結構

ret 實例 保存 傳參 導包 imp scan 創建 內存地址 這是今天的筆記,只是一些理論,後面有幾個練習一塊貼上來了, this:當前類的對象引用使用場合(都是類的內部):1.獲取實例本身 public A getA(){return this}2.獲取類的成員