教面試官ReentrantLock源碼
602
2025-04-03
文章目錄
前言
一、11 種常見的 Java 修飾符
1、修飾符應用表
2、訪問權限對比
二、public 修飾符
三、private 修飾符
四、protected 修飾符
五、default(不加任何訪問權限修飾符)
六、static 修飾符
1、static 修飾成員變量(靜態變量/類變量)
1.1、類變量和實例變量的區別
2、static 修飾成員方法(靜態方法/類方法)
2.1、靜態方法與實例方法的區別和結論
3、static 靜態代碼段
4、static 內部類
七、final 修飾符
八、abstract 修飾符
九、接口(特殊的抽象類)
1、抽象類和接口的區別
2、什么是適配器?
總結
前言
修飾符在 Java 語言中有四種使用情況:成員變量、成員方法、代碼塊和內部類。在日常的開發過程中我們會遇到以下 11 種常見的修飾符,本文將從最基礎的底層和原理幫你理解和疏通這些常見修飾符語法說明以及常見的開發應用案例。
一、11 種常見的 Java 修飾符
1、修飾符應用表
2、訪問權限對比
public > protected > default > private
說明:以下僅介紹我們常用的 7 種修飾符語法說明以及開發應用說明,另外 4 種用法查看修飾符應用表即可。
二、public 修飾符
語法說明:
修飾類、方法、變量。可以在任意位置訪問,公共的。
開發應用:
開發中,通常類和業務方法都使用 public 修飾。
三、private 修飾符
語法說明:
修飾方法、變量、還可以修飾內部類。只能在本類中訪問,私有的。
開發應用:
開發中,通常實體類(Entity,Vo)中的成員變量使用 private 修飾,會提供訪問這些變量的方法 getter 或
setter,原則上要求不準定義私有的方法。
一個實體數據的表通常對應一個實體類。
四、protected 修飾符
語法說明:
修飾方法、變量、還可以修飾內部類。
同一個包可以訪問、子類可以訪問(子類和父類不在同一個包也可以訪問)。
開發應用:
開發中,通常方法或變量是用來繼承的,都使用 protected 修飾。
在繼承中,方法的重寫,子類方法的訪問權限必須大于或等于父類方法的訪問權限。
class Fu { public void play() { } } class Son extends Fu { void play() { } }
五、default(不加任何訪問權限修飾符)
語法說明:
修飾類、方法、變量。
只能在同一個包中訪問,子類也必須在同一個包中。
開發應用:
項目中,類、方法、變量根據需求,通常都會指定訪問權限。
六、static 修飾符
1、static 修飾成員變量(靜態變量/類變量)
語法說明:
Java 中 可以通過 static 關鍵字修飾變量達到全局變量的效果。
static 修飾的變量(靜態變量)屬于類,在類第一次通過類加載器到 jvm 時被分配至方法區。
沒有 static 修飾的變量,稱為實例變量。
1.1、類變量和實例變量的區別
實例變量,在創建對象之后,被分配到堆內存中,實例變量屬于某個具體的對象。當創建對象,實例變量出現在堆內存中,當對象被垃圾回收,實例變量立即釋放內存。
比如:我們創建兩個對象。
Cell c1 = new Cell(4,5); Cell c2 = new Cell(5,6);
當創建對象 c1,c2 時,實例變量(4,5),(5,6)出現在堆內存中,當對象 c1,c2 被垃圾回收,實例變量立即釋放內存。
類變量,被存儲在方法區中,“只有一份”,被所有對象共享。當類被加載的時候,立即被存儲在方法區中,當類被卸載,類變量立即釋放內存。
開發應用:
類變量可以由類名直接訪問,開發中推薦使用類名的全稱。
比如:我們定義一個實體類。
public class Student { // 實例變量,在創建對象之后,被分配到堆內存中,實例變量屬于某個具體的對象 // 當創建對象,實例變量出現在堆內存中,當對象被垃圾回收,實例變量立即釋放內存 String name; // 類變量,被存儲在方法區中,"只有一份",被所有對象共享 static String jtName; public void print() { System.out.println(this.name); System.out.println(jtName); } }
下次使用靜態變量?jtName?時,我們直接使用 Student 這個類名直接調用即可。同時我們也就可以理解下面兩個對象的屬性取值是一樣的。
public class Demo01 { public static void main(String[] args) { // TODO Auto-generated method stub Student stu1 = new Student(); stu1.name = "張三"; stu1.jtName = "王老師"; Student stu2 = new Student(); // 一般直接取類名 // stu2.jtName = "盧老師"; Student.jtName = "盧老師"; System.out.println(stu1.name);// 張三 System.out.println(stu2.name);// null System.out.println(stu1.jtName);// 盧老師 System.out.println(stu2.jtName);// 盧老師 } }
2、static 修飾成員方法(靜態方法/類方法)
靜態方法:static 修飾的方法屬于類方法,不需要創建對象就可以調用。static 方法中不能使用 this 和 super 等關鍵字,不能調用非 static 方法,只能訪問所屬類的靜態成員變量和靜態方法。靜態方法(類方法),當類被加載,靜態方法立即被加載到方法區中,類方法可以由類名直接調用。
實例方法:沒有static修飾的方法,實例方法,當創建對象之后,實例方法立即被加載到方法區中,多個實例共享一份實例方法。
2.1、靜態方法與實例方法的區別和結論
類方法中,不能使用this關鍵字,類方法中不隱含調用該方法對象的參數。
實例方法可以直接調用靜態方法,靜態方法不可以直接訪問實例成員,必須創建對象,由對象訪問。
結論:所有對象共享的數據,定義為靜態變量,否則定義為實例變量方法,方法中沒有訪問實例成員,可以定義為靜態方法。
開發應用:
項目中,通常工具類中的方法,都是靜態的。
3、static 靜態代碼段
語法說明:
JVM在加載類時會執行 static 靜態代碼段,常用于初始化靜態變量。
static代碼只會在類被加載時執行且執行一次。
靜態優于對象。
開發應用:
開發中,通常用于加載靜態資源,讀取配置文件等操作,在靜態代碼段中實現。
比如:我們定義一個工具類如下。
public class SomeUtil { // 默認的無參構造 public SomeUtil() { System.out.println("創建對象!"); } // 靜態優于對象 // 靜態代碼段 當類被加載,立即被執行,一個類在同一個進程中,只加載一次 static { System.out.println("加載靜態資源!"); } // 實例代碼段 { System.out.println("實例代碼段!"); } public static void do1() { System.out.println("do1...."); } public static void do2() { System.out.println("do2...."); } public static void do3() { System.out.println("do3...."); } public static void main(String[] args) { SomeUtil.do1(); SomeUtil.do2(); SomeUtil.do3(); SomeUtil s1 = new SomeUtil(); SomeUtil s2 = new SomeUtil(); } }
執行 main 方法,根據輸出的內容我們可以明確看出執行的順序。靜態代碼段只執行一次,然后是靜態方法被執行,最后是 new 的對象執行無參構造和實例代碼段,new 一次執行一次。同時也可以得出我們的結論:靜態優于對象。
4、static 內部類
語法說明:
static 內部類可以不依賴外部類實例對象而被實例化,而內部類需要在外部類實例化后才能被實例化。
靜態內部類不能訪問外部類的普通變量,只能訪問外部類的靜態成員變量和靜態方法。
七、final 修飾符
語法說明:
final 類,不能被繼承。
final 方法,不能被重寫。
final 修飾的變量,是常量。
開發應用:
開發中,使用 final 定義數據字典。
比如:在如下 Card 類中我們定義數據字典,用于 main 函數的輸出和查詢。
備注:數據字典是指對數據的數據項、數據結構、數據流、數據存儲、處理邏輯等進行定義和描述,其目的是對數據流程圖中的各個元素做出詳細的說明,使用數據字典為簡單的建模項目。簡而言之,數據字典是描述數據的信息集合,是對系統中使用的所有數據元素的定義的集合。
public class Card { // 開發中,使用final定義數據字典。 public static final int SPADE = 1; public static final int HEART = 2; public static final int BLACK = 5; public static final int FLOWER = 6; public static final int THREE = 0; public static final int EIGHT = 5; public static final int JACK = 8; public static final int QUEEN = 9; public static final int KING = 10; public static final int ACE = 11; public static final int DUCE = 12; public static final int JOKER = 13; private int suit; private int num; public Card() { } public Card(int suit, int num) { this.suit = suit; this.num = num; } public int getSuit() { return suit; } public void setSuit(int suit) { this.suit = suit; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public static void main(String[] args) { Card card = new Card(Card.HEART, Card.THREE); System.out.println(card.getNum()); } }
八、abstract 修飾符
語法說明:
抽象的,可以修飾類,修飾方法。
抽象類:
抽象類存在的意義在于被繼承。
抽象類不可以創建對象。
abstract 不能和 final 一起使用 。
抽象方法:
抽象方法,只有定義沒有實現。
如果一個類中有抽象方法,這個類必須是抽象類。
一個抽象類中,可以沒有抽象方法。
抽象類的子類,必須實現父類中所有的抽象方法。
開發應用:
抽象類中既可以有默認實現的方法,又可以有沒有實現的方法。
接口的適配器——用子類去實現接口中的方法。
九、接口(特殊的抽象類)
語法說明:
特殊的抽象類接口中的方法都是抽象方法 接口中的變量都是靜態常量。
定義接口使用 interface 關鍵字。
實現接口使用 implements 關鍵字。
類實現了接口,必須實現接口中所有的方法。
public interface MyInterface { // 接口是高一級別的抽象。不能被實例化,所以只能定義常量 // 定義了變量需要實例化,賦值才能使用,跟接口違背 // 特殊的抽象類 接口中的方法都是抽象方法 接口中的變量都是靜態常量 int I = 10; // 如果類中所有的方法都是抽象方法,使用接口 void method1(); void method2(); }
import java.io.Serializable; /** * 其實適配器只是一個類,它實現了某種接口,提供了方法體。 * 這樣,再用到這個接口時,可以直接繼承適配器,這樣就不需要把接口中的每一個方法再填充一遍了。 * 只需要在這個類中復寫一下需要用的方法。這樣簡單,方便。 * * @author bailu * */ public class MyImpClass implements MyInterface, Serializable { // Serializable序列化 private static final long serialVersionUID = 1L; // 重寫接口的方法——適配器, @Override public void method1() { System.out.println(I); } @Override public void method2() { } }
開發應用:
如果類中所有的方法都是抽象方法,使用接口。
1、抽象類和接口的區別
抽象類中,可以定義抽象方法和非抽象方法。接口中,所有的方法都是抽象方法。
一個類只能繼承一個抽象類。一個類可以實現多個接口,多個接口使用逗號分隔。
比如:如下的類既實現了接口 MyInterface,同時實現了 Serializable 序列化序列化。
import java.io.Serializable; /** - 其實適配器只是一個類,它實現了某種接口,提供了方法體。 - 這樣,再用到這個接口時,可以直接繼承適配器,這樣就不需要把接口中的每一個方法再填充一遍了。 - 只需要在這個類中復寫一下需要用的方法。這樣簡單,方便。 - - @author bailu - */ public class MyImpClass implements MyInterface, Serializable { // Serializable序列化 private static final long serialVersionUID = 1L; // 重寫接口的方法——適配器, @Override public void method1() { System.out.println(I); } @Override public void method2() { } }
抽象類之間也可以繼承,但是也只是支持單繼承。接口之間也可以繼承,一個接口可以繼承多個接口。
開發應用:
接口是用來制定標準或規范。
可以降低組件之間的耦合度,擴展組件的功能。
體現了設計模式中的開閉原則。
2、什么是適配器?
適配器只是一個類,它實現了接口,提供了方法體。再用到這個接口時,可以直接繼承適配器,這樣就不需要把接口中的每一個方法再填充一遍了,只需要在這個類中復寫一下需要用的方法。接口很好地體現了設計模式中的開閉原則。
比如:我們做一個在線商城系統,就需要調用第三方支付——銀行或者是支付寶的支付接口。我們就需要第三方為我們提供接口,里面定義了抽象的方法以及實現接口的方法——適配器,我們通過調用適配器里面的方法來完成支付。
ZsBankInter obj = 獲取實現類對象; obj.send(); 京東、淘寶 銀行接口ZsBankInter send() 類 class DoSend implements ZsBankInter{ send()具體的方法 }
總結
修飾符在 Java 語言中有四種使用情況:成員變量、成員方法、代碼塊和內部類。以上我們總結了在日常的開發過程中會遇到的 11 種常見的修飾符,并從最基礎的底層和原理理解和疏通這些常見修飾符語法說明以及常見的開發應用案例。其中具體的內容還有很多,本文就暫不一一列舉,待日后根據開發需要補充完畢。
Java
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。