JavaSE基礎【吐血整理彙總】
1. 方法
1.1 定義方法的完整格式
-
定義方法的完整格式:
修飾符 返回值型別 方法名稱(引數型別 引數名稱, ...) { 方法體 return 返回值; }
- 修飾符:現階段的固定寫法,public static
- 返回值型別:也就是方法最終產生的資料結果是什麼型別
- 方法名稱:方法的名字,規則和變數一樣,小駝峰
- 引數型別:進入方法的資料是什麼型別
- 引數名稱:進入方法的資料對應的變數名稱
PS:引數如果有多個,使用逗號進行分隔 - 方法體:方法需要做的事情,若干行程式碼
- return:兩個作用,第一停止當前方法,第二將後面的返回值還給呼叫處
- 返回值:也就是方法執行後最終產生的資料結果
注意:return後面的“返回值”,必須和方法名稱前面的“返回值型別”,保持對應。
-
定義一個兩個int數字相加的方法。三要素:
- 返回值型別:int
- 方法名稱:sum
- 引數列表:int a, int b
-
方法的三種呼叫格式。
- 單獨呼叫:方法名稱(引數);
- 列印呼叫:System.out.println(方法名稱(引數));
- 賦值呼叫:資料型別 變數名稱 = 方法名稱(引數);
注意:此前學習的方法,返回值型別固定寫為void,這種方法只能夠單獨呼叫,不能進行列印呼叫或者賦值呼叫。
1.2 有無引數的方法
- 有引數:小括號當中有內容,當一個方法需要一些資料條件,才能完成任務的時候,就是有引數。
例如兩個數字相加,必須知道兩個數字是各自多少,才能相加。 - 無引數:小括號當中留空。一個方法不需要任何資料條件,自己就能獨立完成任務,就是無引數。
例如定義一個方法,列印固定10次HelloWorld。
1.3 使用方法注意事項
- 方法應該定義在類當中,但是不能在方法當中再定義方法。不能巢狀。
- 方法定義的前後順序無所謂。
- 方法定義之後不會執行,如果希望執行,一定要呼叫:單獨呼叫、列印呼叫、賦值呼叫。
- 如果方法有返回值,那麼必須寫上“return 返回值;”,不能沒有。
- return後面的返回值資料,必須和方法的返回值型別,對應起來。
- 對於一個void沒有返回值的方法,不能寫return後面的返回值,只能寫return自己。
- 對於void方法當中最後一行的return可以省略不寫。
- 一個方法當中可以有多個return語句,但是必須保證同時只有一個會被執行到,兩個return不能連寫。
1.4 方法的過載
- 對於功能類似的方法來說,因為引數列表不一樣,卻需要記住那麼多不同的方法名稱,太麻煩。
- 方法的過載(Overload):多個方法的名稱一樣,但是引數列表不一樣。
- 好處:只需要記住唯一一個方法名稱,就可以實現類似的多個功能。
- 方法過載與下列因素相關:
- 引數個數不同
- 引數型別不同
- 引數的多型別順序不同
- 方法過載與下列因素無關:
- 與引數的名稱無關
- 與方法的返回值型別無關
2. 陣列
2.1 陣列的概念與特點
- 陣列的概念:是一種容器,可以同時存放多個數據值。
- 陣列的特點:
- 陣列是一種引用資料型別
- 陣列當中的多個數據,型別必須統一
- 陣列的長度在程式執行期間不可改變
- 陣列的初始化:在記憶體當中建立一個數組,並且向其中賦予一些預設值。
- 兩種常見的初始化方式:
- 動態初始化(指定長度)
- 靜態初始化(指定內容)
- 動態初始化陣列的格式:
資料型別[] 陣列名稱 = new 資料型別[陣列長度];- 解析含義:
- 左側資料型別:也就是陣列當中儲存的資料,全都是統一的什麼型別
- 左側的中括號:代表我是一個數組
- 左側陣列名稱:給陣列取一個名字
- 右側的new:代表建立陣列的動作
- 右側資料型別:必須和左邊的資料型別保持一致
- 右側中括號的長度:也就是陣列當中,到底可以儲存多少個數據,是一個int數字
2.2 動態初始化與靜態初始化
- 動態初始化(指定長度):在建立陣列的時候,直接指定陣列當中的資料元素個數。
- 靜態初始化(指定內容):在建立陣列的時候,不直接指定資料個數多少,而是直接將具體的資料內容進行指定。
- 靜態初始化基本格式:
- 資料型別[] 陣列名稱 = new 資料型別[] { 元素1, 元素2, … };
- 注意事項:
- 雖然靜態初始化沒有直接告訴長度,但是根據大括號裡面的元素具體內容,也可以自動推算出來長度。
2.3 靜態初始化格式
- 使用靜態初始化陣列的時候,格式還可以省略一下。
- 標準格式:
- 資料型別[] 陣列名稱 = new 資料型別[] { 元素1, 元素2, … };
- 省略格式:
- 資料型別[] 陣列名稱 = { 元素1, 元素2, … };
- 注意事項:
- 靜態初始化沒有直接指定長度,但是仍然會自動推算得到長度。
- 靜態初始化標準格式可以拆分成為兩個步驟。
- 動態初始化也可以拆分成為兩個步驟。
- 靜態初始化一旦使用省略格式,就不能拆分成為兩個步驟了。
- 使用建議:
- 如果不確定陣列當中的具體內容,用動態初始化;否則,已經確定了具體的內容,用靜態初始化。
2.4 陣列索引
- 陣列的索引編號從0開始,一直到“陣列的長度-1”為止。
- 如果訪問陣列元素的時候,索引編號並不存在,那麼將會發生
陣列索引越界異常
ArrayIndexOutOfBoundsException - 原因:索引編號寫錯了。
解決:修改成為存在的正確索引編號。
3. 面向物件
面向過程:當需要實現一個功能的時候,每一個具體的步驟都要親力親為,詳細處理每一個細節。
面向物件:當需要實現一個功能的時候,不關心具體的步驟,而是找一個已經具有該功能的人,來幫我做事兒。
3.1 new物件
- 通常情況下,一個類並不能直接使用,需要根據類建立一個物件,才能使用。
- 導包:也就是指出需要使用的類,在什麼位置。
import 包名稱.類名稱;
import cn.itcast.day06.demo01.Student;
對於和當前類屬於同一個包的情況,可以省略導包語句不寫。 - 建立,格式:
類名稱 物件名 = new 類名稱();
Student stu = new Student(); - 使用,分為兩種情況:
使用成員變數:物件名.成員變數名
使用成員方法:物件名.成員方法名(引數)
(也就是,想用誰,就用物件名點兒誰。)
- 注意事項:
- 如果成員變數沒有進行賦值,那麼將會有一個預設值,規則和陣列一樣。
3.2 區域性變數和成員變數
-
定義的位置不一樣【重點】
區域性變數:在方法的內部
成員變數:在方法的外部,直接寫在類當中 -
作用範圍不一樣【重點】
區域性變數:只有方法當中才可以使用,出了方法就不能再用
成員變數:整個類全都可以通用。 -
預設值不一樣【重點】
區域性變數:沒有預設值,如果要想使用,必須手動進行賦值
成員變數:如果沒有賦值,會有預設值,規則和陣列一樣 -
記憶體的位置不一樣(瞭解)
區域性變數:位於棧記憶體
成員變數:位於堆記憶體 -
生命週期不一樣(瞭解)
區域性變數:隨著方法進棧而誕生,隨著方法出棧而消失
成員變數:隨著物件建立而誕生,隨著物件被垃圾回收而消失
3.3 面向物件三大特徵
- 面向物件三大特徵:封裝、繼承、多型
- 封裝性在Java當中的體現:
- 方法就是一種封裝
- 關鍵字private也是一種封裝
- 封裝就是將一些細節資訊隱藏起來,對於外界不可見。
3.4 封裝
- 問題描述:定義Person的年齡時,無法阻止不合理的數值被設定進來。
- 解決方案:用private關鍵字將需要保護的成員變數進行修飾。
- 一旦使用了private進行修飾,那麼本類當中仍然可以隨意訪問。
但是!超出了本類範圍之外就不能再直接訪問了。 - 間接訪問private成員變數,就是定義一對兒Getter/Setter方法
- 必須叫setXxx或者是getXxx命名規則。
- 對於Getter來說,不能有引數,返回值型別和成員變數對應;
- 對於Setter來說,不能有返回值,引數型別和成員變數對應。
3.5 構造方法
- 構造方法是專門用來建立物件的方法,當我們通過關鍵字new來建立物件時,其實就是在呼叫構造方法。
- 格式:
public 類名稱(引數型別 引數名稱) { 方法體 }
- 注意事項:
- 構造方法的名稱必須和所在的類名稱完全一樣,就連大小寫也要一樣
- 構造方法不要寫返回值型別,連void都不寫
- 構造方法不能return一個具體的返回值
- 如果沒有編寫任何構造方法,那麼編譯器將會預設贈送一個構造方法,沒有引數、方法體什麼事情都不做。
public Student() {} - 一旦編寫了至少一個構造方法,那麼編譯器將不再贈送。
- 構造方法也是可以進行過載的。
過載:方法名稱相同,引數列表不同。
3.6 Java Bean
- 一個標準的類通常要擁有下面四個組成部分:
- 所有的成員變數都要使用private關鍵字修飾
- 為每一個成員變數編寫一對兒Getter/Setter方法
- 編寫一個無引數的構造方法
- 編寫一個全引數的構造方法
- 這樣標準的類也叫做Java Bean
4. Scanner類
- Scanner類的功能:可以實現鍵盤輸入資料,到程式當中。
- 引用型別的一般使用步驟:
- 導包
import 包路徑.類名稱;
如果需要使用的目標類,和當前類位於同一個包下,則可以省略導包語句不寫。
只有java.lang包下的內容不需要導包,其他的包都需要import語句。 - 建立
類名稱 物件名 = new 類名稱(); - 使用
物件名.成員方法名()
- 導包
- 獲取鍵盤輸入的一個int數字:int num = sc.nextInt();
- 獲取鍵盤輸入的一個字串:String str = sc.next();
4.1 new物件格式
- 建立物件的標準格式:
- 類名稱 物件名 = new 類名稱();
- 匿名物件就是隻有右邊的物件,沒有左邊的名字和賦值運算子。
- new 類名稱();
- 注意事項:匿名物件只能使用唯一的一次,下次再用不得不再建立一個新物件。
- 使用建議:如果確定有一個物件只需要使用唯一的一次,就可以用匿名物件。
5. Random類
- Random類用來生成隨機數字。使用起來也是三個步驟:
- 導包
import java.util.Random; - 建立
Random r = new Random(); // 小括號當中留空即可 - 使用
獲取一個隨機的int數字(範圍是int所有範圍,有正負兩種):int num = r.nextInt()
獲取一個隨機的int數字(引數代表了範圍,左閉右開區間):int num = r.nextInt(3)
實際上代表的含義是:[0,3),也就是0~2
6. 陣列與集合的區別
- 陣列的長度不可以發生改變。
- 但是ArrayList集合的長度是可以隨意變化的。
- 對於ArrayList來說,有一個尖括號代表泛型。
- 泛型:也就是裝在集合當中的所有元素,全都是統一的什麼型別。
- 注意:泛型只能是引用型別,不能是基本型別。
- 注意事項:
- 對於ArrayList集合來說,直接列印得到的不是地址值,而是內容。
- 如果內容是空,得到的是空的中括號:[]
7. 包裝類
- 如果希望向集合ArrayList當中儲存基本型別資料,必須使用基本型別對應的“包裝類”。
基本型別 包裝類(引用型別,包裝類都位於java.lang包下) byte Byte short Short int Integer 【特殊】 long Long float Float double Double char Character 【特殊】 boolean Boolean - 從JDK 1.5+開始,支援自動裝箱、自動拆箱。
- 自動裝箱:基本型別 --> 包裝型別
- 自動拆箱:包裝型別 --> 基本型別
8. String類
java.lang.String類代表字串。
API當中說:Java 程式中的所有字串字面值(如 “abc” )都作為此類的例項實現。
其實就是說:程式當中所有的雙引號字串,都是String類的物件。(就算沒有new,也照樣是。)
- 字串的特點:
- 字串的內容永不可變。【重點】
- 正是因為字串不可改變,所以字串是可以共享使用的。
- 字串效果上相當於是char[]字元陣列,但是底層原理是byte[]位元組陣列。
建立字串的常見3+1種方式。
- 三種構造方法:
- public String():建立一個空白字串,不含有任何內容。
- public String(char[] array):根據字元陣列的內容,來建立對應的字串。
- public String(byte[] array):根據位元組陣列的內容,來建立對應的字串。
- 一種直接建立:
- String str = “Hello”; // 右邊直接用雙引號
注意:直接寫上雙引號,就是字串物件。
- String str = “Hello”; // 右邊直接用雙引號
8.1 String類方法使用
- public int length():獲取字串當中含有的字元個數,拿到字串長度。
- public String concat(String str):將當前字串和引數字串拼接成為返回值新的字串。
- public char charAt(int index):獲取指定索引位置的單個字元。(索引從0開始。)
- public int indexOf(String str):查詢引數字串在本字串當中首次出現的索引位置,如果沒有返回-1值。
- public String substring(int index):擷取從引數位置一直到字串末尾,返回新字串。
- public String substring(int begin, int end):擷取從begin開始,一直到end結束,中間的字串。
備註:[begin,end),包含左邊,不包含右邊。
- public char[] toCharArray():將當前字串拆分成為字元陣列作為返回值。
- public byte[] getBytes():獲得當前字串底層的位元組陣列。
- public String replace(CharSequence oldString, CharSequence newString):
將所有出現的老字串替換成為新的字串,返回替換之後的結果新字串。
備註:CharSequence意思就是說可以接受字串型別。
- public String[] split(String regex):按照引數的規則,將字串切分成為若干部分。
注意事項:
split方法的引數其實是一個“正則表示式”,今後學習。
今天要注意:如果按照英文句點“.”進行切分,必須寫"\\."(兩個反斜槓)
9. static關鍵字
如果一個成員變數使用了static關鍵字,那麼這個變數不再屬於物件自己,而是屬於所在的類。多個物件共享同一份資料。
9.1 static關鍵字注意事項
- 一旦使用static修飾成員方法,那麼這就成為了靜態方法。靜態方法不屬於物件,而是屬於類的。
- 如果沒有static關鍵字,那麼必須首先建立物件,然後通過物件才能使用它。
- 如果有了static關鍵字,那麼不需要建立物件,直接就能通過類名稱來使用它。
- 無論是成員變數,還是成員方法。如果有了static,都推薦使用類名稱進行呼叫。
- 靜態變數:類名稱.靜態變數
- 靜態方法:類名稱.靜態方法()
- 注意事項:
- 靜態不能直接訪問非靜態。
原因:因為在記憶體當中是【先】有的靜態內容,【後】有的非靜態內容。
“先人不知道後人,但是後人知道先人。” - 靜態方法當中不能用this。
原因:this代表當前物件,通過誰呼叫的方法,誰就是當前物件。
- 靜態不能直接訪問非靜態。
9.2 靜態程式碼塊
- 靜態程式碼塊的格式是:
public class 類名稱 { static { // 靜態程式碼塊的內容 } }
- 特點:當第一次用到本類時,靜態程式碼塊執行唯一的一次。
靜態內容總是優先於非靜態,所以靜態程式碼塊比構造方法先執行。 - 靜態程式碼塊的典型用途:
用來一次性地對靜態成員變數進行賦值。
10. Math類
- java.util.Math類是數學相關的工具類,裡面提供了大量的靜態方法,完成與數學運算相關的操作。
public static double abs(double num):獲取絕對值。有多種過載。
public static double ceil(double num):向上取整。
public static double floor(double num):向下取整。
public static long round(double num):四捨五入。
- Math.PI代表近似的圓周率常量(double)。
11. 繼承
- 在繼承的關係中,“子類就是一個父類”。也就是說,子類可以被當做父類看待。
- 例如父類是員工,子類是講師,那麼“講師就是一個員工”。關係:is-a。
- 定義父類的格式:(一個普通的類定義)
public class 父類名稱 { // ... }
- 定義子類的格式:
public class 子類名稱 extends 父類名稱 { // ... }
11.1 繼承訪問成員變數
- 在父子類的繼承關係當中,如果成員變數重名,則建立子類物件時,訪問有兩種方式:
- 直接通過子類物件訪問成員變數:
- 等號左邊是誰,就優先用誰,沒有則向上找。
- 間接通過成員方法訪問成員變數:
- 該方法屬於誰,就優先用誰,沒有則向上找。
- 直接通過子類物件訪問成員變數:
11.2 繼承中變數的訪問
- 區域性變數: 直接寫成員變數名
- 本類的成員變數: this.成員變數名
- 父類的成員變數: super.成員變數名
11.3 繼承中方法重寫
- 在父子類的繼承關係當中,建立子類物件,訪問成員方法的規則:
- 建立的物件是誰,就優先用誰,如果沒有則向上找。
- 注意事項:
- 無論是成員方法還是成員變數,如果沒有都是向上找父類,絕對不會向下找子類的。
- 重寫(Override)
- 概念:在繼承關係當中,方法的名稱一樣,引數列表也一樣。
- 重寫(Override):方法的名稱一樣,引數列表【也一樣】。覆蓋、覆寫。
- 方法的覆蓋重寫特點:建立的是子類物件,則優先用子類方法。
- 過載(Overload):方法的名稱一樣,引數列表【不一樣】。
11.4 方法覆蓋重寫的注意事項
- 必須保證父子類之間方法的名稱相同,引數列表也相同。
- @Override:寫在方法前面,用來檢測是不是有效的正確覆蓋重寫。
- 這個註解就算不寫,只要滿足要求,也是正確的方法覆蓋重寫。
- 子類方法的返回值必須【小於等於】父類方法的返回值範圍。
- 小擴充套件提示:java.lang.Object類是所有類的公共最高父類(祖宗類),java.lang.String就是Object的子類。
- 子類方法的許可權必須【大於等於】父類方法的許可權修飾符。
- 小擴充套件提示:public > protected > (default) > private
- 備註:(default)不是關鍵字default,而是什麼都不寫,留空。
11.5 繼承中構造方法訪問
- 繼承關係中,父子類構造方法的訪問特點:
- 子類構造方法當中有一個預設隱含的“super()”呼叫,所以一定是先呼叫的父類構造,後執行的子類構造。
- 子類構造可以通過super關鍵字來呼叫父類過載構造。
- super的父類構造呼叫,必須是子類構造方法的第一個語句。不能一個子類構造呼叫多次super構造。
- 總結:
- 子類必須呼叫父類構造方法,不寫則贈送super();
- 寫了則用寫的指定的super呼叫,super只能有一個,還必須是第一個。
12. 抽象
- 抽象方法:就是加上abstract關鍵字,然後去掉大括號,直接分號結束。
- 抽象類:抽象方法所在的類,必須是抽象類才行。在class之前寫上abstract即可。
- 如何使用抽象類和抽象方法:
- 不能直接建立new抽象類物件。
- 必須用一個子類來繼承抽象父類。
- 子類必須覆蓋重寫抽象父類當中所有的抽象方法。
覆蓋重寫(實現):子類去掉抽象方法的abstract關鍵字,然後補上方法體大括號。 - 建立子類物件進行使用。
13. 介面
- 介面就是多個類的公共規範。
- 介面是一種引用資料型別,最重要的內容就是其中的:抽象方法。
- 如何定義一個介面的格式:
public interface 介面名稱 { // 介面內容 }
- 備註:換成了關鍵字interface之後,編譯生成的位元組碼檔案仍然是:.java --> .class。
- 如果是Java 7,那麼介面中可以包含的內容有:
- 常量
- 抽象方法
- 如果是Java 8,還可以額外包含有:
3. 預設方法
4. 靜態方法 - 如果是Java 9,還可以額外包含有:
5. 私有方法 - 介面使用步驟:
- 介面不能直接使用,必須有一個“實現類”來“實現”該介面。
格式:public class 實現類名稱 implements 介面名稱 { // ... }
- 介面的實現類必須覆蓋重寫(實現)介面中所有的抽象方法。
實現:去掉abstract關鍵字,加上方法體大括號。 - 建立實現類的物件,進行使用。
- 介面不能直接使用,必須有一個“實現類”來“實現”該介面。
- 注意事項:
- 如果實現類並沒有覆蓋重寫介面中所有的抽象方法,那麼這個實現類自己就必須是抽象類。
13.1 介面實現重點
- 介面的預設方法,可以通過介面實現類物件,直接呼叫。
- 介面的預設方法,也可以被介面實現類進行覆蓋重寫。
13.2 介面中靜態方法的呼叫
- 注意事項:不能通過介面實現類的物件來呼叫介面當中的靜態方法。
- 正確用法:通過介面名稱,直接呼叫其中的靜態方法。
- 格式:
- 介面名稱.靜態方法名(引數);
13.3 介面中定義抽象方法
- 在任何版本的Java中,介面都能定義抽象方法。
- 格式:
public abstract 返回值型別 方法名稱(引數列表); - 注意事項:
- 介面當中的抽象方法,修飾符必須是兩個固定的關鍵字:public abstract
- 這兩個關鍵字修飾符,可以選擇性地省略。(今天剛學,所以不推薦。)
- 方法的三要素,可以隨意定義。
13.4 介面中的常量
- 介面當中也可以定義“成員變數”,但是必須使用public static final三個關鍵字進行修飾。
- 從效果上看,這其實就是介面的【常量】。
- 格式:
public static final 資料型別 常量名稱 = 資料值; - 備註:
一旦使用final關鍵字進行修飾,說明不可改變。 - 注意事項:
- 介面當中的常量,可以省略public static final,注意:不寫也照樣是這樣。
- 介面當中的常量,必須進行賦值;不能不賦值。
- 介面中常量的名稱,使用完全大寫的字母,用下劃線進行分隔。(推薦命名規則)
13.5 介面定義預設方法
- 從Java 8開始,接口裡允許定義預設方法。
- 格式
public default 返回值型別 方法名稱(引數列表) { 方法體 }
- 備註:介面當中的預設方法,可以解決介面升級的問題。
- 【私有方法】
- 問題描述:
- 我們需要抽取一個共有方法,用來解決兩個預設方法之間重複程式碼的問題。
- 但是這個共有方法不應該讓實現類使用,應該是私有化的。
- 解決方案:
- 從Java 9開始,介面當中允許定義私有方法。
- 普通私有方法,解決多個預設方法之間重複程式碼問題
- 格式
private 返回值型別 方法名稱(引數列表) { 方法體 }
- 靜態私有方法,解決多個靜態方法之間重複程式碼問題
- 格式:
private static 返回值型別 方法名稱(引數列表) { 方法體 }
- 問題描述:
13.6 介面定義靜態方法
- 從Java 8開始,介面當中允許定義靜態方法。
- 格式:
public static 返回值型別 方法名稱(引數列表) { 方法體 }
- 提示:就是將abstract或者default換成static即可,帶上方法體。
13.7 介面使用注意事項
- 介面是沒有靜態程式碼塊或者構造方法的。
- 一個類的直接父類是唯一的,但是一個類可以同時實現多個介面。
- 格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { // 覆蓋重寫所有抽象方法 }
- 如果實現類所實現的多個介面當中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。
- 如果實現類沒有覆蓋重寫所有介面當中的所有抽象方法,那麼實現類就必須是一個抽象類。
- 如果實現類鎖實現的多個介面當中,存在重複的預設方法,那麼實現類一定要對衝突的預設方法進行覆蓋重寫。
- 一個類如果直接父類當中的方法,和介面當中的預設方法產生了衝突,優先用父類當中的方法。
13.8 類與介面的關係
- 類與類之間是單繼承的。直接父類只有一個。
- 類與介面之間是多實現的。一個類可以實現多個介面。
- 介面與介面之間是多繼承的。
- 注意事項:
- 多個父介面當中的抽象方法如果重複,沒關係。
- 多個父介面當中的預設方法如果重複,那麼子介面必須進行預設方法的覆蓋重寫,【而且帶著default關鍵字】。
14. 多型
- 程式碼當中體現多型性,其實就是一句話:父類引用指向子類物件。
- 格式:
父類名稱 物件名 = new 子類名稱();
或者:
介面名稱 物件名 = new 實現類名稱();
14.1 多型訪問
- 在多型的程式碼當中,成員方法的訪問規則是:
- 看new的是誰,就優先用誰,沒有則向上找。
- 口訣:編譯看左邊,執行看右邊。
- 對比一下:
- 成員變數:編譯看左邊,執行還看左邊。
- 成員方法:編譯看左邊,執行看右邊。
14.2 向上向下轉型
- 向上轉型一定是安全的,沒有問題的,正確的。但是也有一個弊端:
- 物件一旦向上轉型為父類,那麼就無法呼叫子類原本特有的內容。
- 解決方案:用物件的向下轉型【還原】。
15. final關鍵字
- final關鍵字代表最終、不可改變的。
- 常見四種用法:
- 可以用來修飾一個類
- 可以用來修飾一個方法
- 還可以用來修飾一個區域性變數
- 還可以用來修飾一個成員變數
15.1 final修飾方法
- 當final關鍵字用來修飾一個方法的時候,這個方法就是最終方法,也就是不能被覆蓋重寫。
- 格式:
修飾符 final 返回值型別 方法名稱(引數列表) { // 方法體 }
- 注意事項:
- 對於類、方法來說,abstract關鍵字和final關鍵字不能同時使用,因為矛盾。
15.2 final修飾類
- 當final關鍵字用來修飾一個類的時候,格式:
public final class 類名稱 { // ... }
- 含義:當前這個類不能有任何的子類。(太監類)
- 注意:一個類如果是final的,那麼其中所有的成員方法都無法進行覆蓋重寫(因為沒兒子。)
15.3 final修飾成員變數
- 對於成員變數來說,如果使用final關鍵字修飾,那麼這個變數也照樣是不可變。
- 由於成員變數具有預設值,所以用了final之後必須手動賦值,不會再給預設值了。
- 對於final的成員變數,要麼使用直接賦值,要麼通過構造方法賦值。二者選其一。
- 必須保證類當中所有過載的構造方法,都最終會對final的成員變數進行賦值。
16. Java中有四種許可權修飾符
範圍 | public | protected | (default) | private |
---|---|---|---|---|
同一個類(我自己) | YES | YES | YES | YES |
同一個包(我鄰居) | YES | YES | YES | NO |
不同包子類(我兒子) | YES | YES | NO | NO |
不同包非子類(陌生人) | YES | NO | NO | NO |
注意事項:(default)並不是關鍵字“default”,而是根本不寫。
17. 內部類
- 如果一個事物的內部包含另一個事物,那麼這就是一個類內部包含另一個類。
- 例如:身體和心臟的關係。又如:汽車和發動機的關係。
- 分類:
- 成員內部類
- 區域性內部類(包含匿名內部類)
- 成員內部類的定義格式:
修飾符 class 外部類名稱 { 修飾符 class 內部類名稱 { // ... } // ... }
注意:內用外,隨意訪問;外用內,需要內部類物件。
17.1 成員內部類
- 如何使用成員內部類?有兩種方式:
- 間接方式:在外部類的方法當中,使用內部類;然後main只是呼叫外部類的方法。
- 直接方式,公式:
類名稱 物件名 = new 類名稱();
【外部類名稱.內部類名稱 物件名 = new 外部類名稱().new 內部類名稱();】
17.2 區域性內部類1
- 區域性內部類,如果希望訪問所在方法的區域性變數,那麼這個區域性變數必須是【有效final的】。
- 備註:從Java 8+開始,只要區域性變數事實不變,那麼final關鍵字可以省略。
- 原因:
- new出來的物件在堆記憶體當中。
- 區域性變數是跟著方法走的,在棧記憶體當中。
- 方法執行結束之後,立刻出棧,區域性變數就會立刻消失。
- 但是new出來的物件會在堆當中持續存在,直到垃圾回收消失。
17.3 區域性內部類2
- 如果一個類是定義在一個方法內部的,那麼這就是一個區域性內部類。
- “區域性”:只有當前所屬的方法才能使用它,出了這個方法外面就不能用了。
- 定義格式:
修飾符 class 外部類名稱 { 修飾符 返回值型別 外部類方法名稱(引數列表) { class 區域性內部類名稱 { // ... } } }
17.4 類的許可權修飾符
- public > protected > (default) > private
- 定義一個類的時候,許可權修飾符規則:
- 外部類:public / (default)
- 成員內部類:public / protected / (default) / private
- 區域性內部類:什麼都不能寫
17.5 匿名內部類
- 如果介面的實現類(或者是父類的子類)只需要使用唯一的一次,
那麼這種情況下就可以省略掉該類的定義,而改為使用【匿名內部類】。 - 匿名內部類的定義格式:
介面名稱 物件名 = new 介面名稱() { // 覆蓋重寫所有抽象方法 };
- 對格式“new 介面名稱() {…}”進行解析:
- new代表建立物件的動作
- 介面名稱就是匿名內部類需要實現哪個介面
- {…}這才是匿名內部類的內容
- 另外還要注意幾點問題:
- 匿名內部類,在【建立物件】的時候,只能使用唯一一次。
如果希望多次建立物件,而且類的內容一樣的話,那麼就需要使用單獨定義的實現類了。 - 匿名物件,在【呼叫方法】的時候,只能呼叫唯一一次。
如果希望同一個物件,呼叫多次方法,那麼必須給物件起個名字。 - 匿名內部類是省略了【實現類/子類名稱】,但是匿名物件是省略了【物件名稱】
強調:匿名內部類和匿名物件不是一回事!!!
- 匿名內部類,在【建立物件】的時候,只能使用唯一一次。