15.Java this 關鍵字/static關鍵字/靜態初始化塊
阿新 • • 發佈:2021-11-06
Java 的 this 關鍵字、static關鍵字、靜態初始化塊
建立物件的過程
- 分配物件空間,並將物件成員初始化為 0 或 空
- 執行屬性值的顯式初始化
- 執行構造方法
- 返回物件的地址給相關的變數。
this 關鍵字
注意點
- this 關鍵字用於區分區域性變數和成員變數。(就近原則:優先獲取最近的)
- 通過 this 可以直接指代成員變數(屬性)。
- 通過 this 可以去呼叫類中普通的成員方法。
- 通過 this 可以去呼叫構造器。使用 this 關鍵字在一個構造器中去呼叫另一個過載的構造方法,可以避免相同的初始化程式碼。但只能在構造方法中用,且必須位於構造方法程式碼的第一行,否則報錯。
- this 不能用於 static 方法中
- 在程式產生二義性之處,應用 this 來指明當前物件;
- 普通方法中,this 總是指向呼叫該方法的物件。
- 構造方法中,this 總是指向正要初始化的物件。
程式碼示例:上方注意點中提到的程式碼
public class TestThis1 { int a,b,c; // 定義構造方法 TestThis1(int a,int b){ this.a = a; this.b = b; } // 構造方法的過載 TestThis1(int a,int b,int c){ // 呼叫本類中(上方)兩個引數的構造方法。在一個構造器中呼叫另一個構造器。 this(a,b); this.c = c; } // 定義普通方法 void sing(){ System.out.println("小明同學,小明同學"); } // 定義普通方法 void eat() { // 呼叫本類中的 sing() 方法 this.sing(); System.out.println("小明同學,小明同學,你媽媽給你送來了你最喜歡的旺仔牛奶。"); } public static void main(String[] args) { // 建立類物件,呼叫類方法(如果自定義了構造方法,則系統就不會自動新增無參構造方法,建立物件時就需要指定是哪個構造方法) TestThis1 hi = new TestThis1(2,3); hi.eat(); } }
程式碼示例:this 代表 “當前物件”
public class User { // 定義類的成員變數(類屬性) int id; // id String name;// 賬戶名 String pwd; // 密碼 // 定義空構造方法 public User(){ } // 構造方法過載 public User(int id,String name){ // 測試呼叫方法時的 實參 到底是賦值給了誰 System.out.println(id); // 列印結果為 119 System.out.println(name); // 列印結果為 阿jun System.out.println(pwd); // 列印結果為 null System.out.println("正在初始化已經建立好的物件(當前物件):" + this); // 利用 this 關鍵字將成員變數賦值給 User 構造方法的區域性變數 this.id = id; // 不寫 this,無法區分區域性變數 id 和 成員變數 id this.name = name; } // 定義普通方法 public void login(){ // 這裡的 this.name 等同於方法裡呼叫成員變數(屬性) name System.out.println(this.name + ",要登入!"); // 不寫 this 效果一樣 } // 定義 main 方法 public static void main(String[] args) { // 呼叫方法時,成員變數屬性 id 和 name 都已經被分別賦值為 id=119 和 name="阿jun" // 呼叫方法時定義的實參是直接賦值給了外部對應的成員變數(也叫對應類屬性) User u3 = new User(119,"阿jun"); // 此時列印的是 User 類中 u3 物件的記憶體地址 System.out.println("列印的是 User 類中 u3 物件的記憶體地址:" + u3); u3.login(); } }
static 關鍵字
簡述
在類中,用 static 修飾的變數稱之為靜態變數,也稱為類變數。
類變數的宣告週期和類相同,在整個應用程式執行期間都有效。
如下特點:
- 類表裡是該類的公用變數,屬於類,被該類的所有例項共享,在類被載入時被顯式初始化。
- 對於該類的所有物件來說,static 成員變數只有一份,被該類的所有物件共享。
- 一般用 “類名.屬性/方法” 來呼叫。(也可以通過物件引用或類名(不需要例項化)訪問靜態成員。)
- 在 static 方法中,不可直接訪問非 static 的成員。
核心要點:
- static 修飾的成員變數和方法,從屬於類。
- 普通變數和方法從屬於物件。
程式碼示例:測試 static 關鍵字的用法
// 測試 static 關鍵字的用法
public class User2 {
int id;
String name;
String pwd;
static String company = "公眾號:阿jun修煉手冊"; // 定義靜態變數
// 定義構造方法
public User2(int id,String name){
this.id = id;
this.name = name;
}
// 定義普通方法
public void login(){
// 普通方法中呼叫靜態方法
printCompany();
// 普通方法中呼叫靜態變數
System.out.println("登入名:" + company);
// 普通方法中呼叫普通屬性
System.out.println("登入名:" + id);
}
// 定義靜態方法
public static void printCompany(){
System.out.println(company);
// 編譯出錯,靜態方法中無法去使用非靜態的方法/變數/常量,因為兩者在方法區中的位置不同
// System.out.println(id);
}
public static void main(String[] args) {
// 定義類物件,類物件不能去呼叫靜態方法/常量/變數
User2 u = new User2(110, "120");
// 通過類名去呼叫方法,列印 company 靜態變數
User2.printCompany();
// 靜態變數重新賦值,通過類名去呼叫 company 靜態變數
User2.company = "阿jun 都2021年了還沒物件";
// 通過類名去呼叫方法,列印 company 靜態變數
User2.printCompany();
// 物件呼叫靜態方法
u.printCompany();
// 物件呼叫普通方法
u.login();
}
}
記憶體分析圖
注意點
- 類載入完以後,類裡面的相關資訊(程式碼、靜態變數/常量)會載入到 方法區 中
- 普通的方法/變數/常量 從屬於類物件
- 靜態的方法/變數/常量 從屬於類。
- 靜態方法中無法去使用非靜態的方法/變數/常量。因為兩者在記憶體的堆中的位置不同
- 在普通方法中呼叫靜態的方法/屬性,沒有問題
- this 用於普通方法中,屬於類,不屬於物件,this 代表的是當前的物件,所以不能在靜態方法裡使用
- 靜態方法/變數/常量 類似於汽車的圖紙,非靜態方法/變數/常量屬類似於汽車成品。圖紙中不能找到汽車,汽車中能去找圖紙(有汽車,肯定就有圖紙,有圖紙不一定有汽車)
靜態初始化塊
簡述
構造方法用於物件的初始化。靜態初始化塊,用於類的初始化操作。
在靜態初始化塊中不能直接訪問非 static 成員。
語法格式
static {
…………
}
使用要點
- 靜態塊用 static 來修飾,不給定名字。
- 靜態塊在類初始化的時候開始執行。
- 類初始化過程中,不能去呼叫非靜態的方法/變數,因為初始化過程中沒有物件。
- 初始化類的過程,相當於是在描繪汽車圖紙的過程。
- 程式在載入類的過程中,就會去將靜態塊的程式碼內容去執行。
- 類載入完成以後,才能構造物件。
程式碼示例:測試靜態初始化塊的使用
// 測試 靜態初始化塊
public class User3 {
int id;
String name;
String pwd;
static String company; // 定義靜態成員變數
// 靜態初始化塊
static {
System.out.println("開始進行類的靜態初始化塊,company 此時的值為:" + company);
System.out.println("靜態初始化塊會在類載入的時候被呼叫執行。");
System.out.println("靜態初始化塊可以去呼叫靜態的方法/變數,但不能呼叫非靜態的方法/變數(如:id、name)");
// 呼叫靜態成員變數並賦值
company = "公眾號-阿jun修煉手冊";
// 呼叫靜態方法
printCompany();
}
// 定義靜態方法
public static void printCompany(){
// 靜態方法中呼叫靜態變數
System.out.println("被賦值以後的 company 值為:" + company);
}
public static void main(String[] args) {
User3 u = null; // 這裡並沒有建立物件,啥也沒做
}
}
注意點
靜態初始化執行順序(學繼承以後再看,先了解)
- 上溯到 Object 類,先執行 Object 的靜態初始化塊,再向下執行子類的靜態初始化塊,知道我們的類靜態初始化塊為止。
- 構造方法執行順序與上方所述一致。