8、強制優先順序、權重疊加、標記的顯示模式
目錄:
一、Java 概述
- Java體系
- 常用的DOS命令
- JDK、JRE、跨平臺、Java平臺
- Java程式碼的編寫執行過程
- 註釋
- 關鍵字、識別符號
- Java中的資料型別
- Java中的常量
二、變數和運算子
- 變數和計算機儲存單元
- 資料型別和常量
- 資料型別轉換
- 運算子 和 優先順序
三、引用資料型別、流程控制語句 和 陣列
- 引用資料型別
- 流程控制語句
- 陣列
四、方法
- 引入
- 語法格式
- 方法呼叫
- 注意事項
- 方法過載
- 可變引數列表
五,面向物件三大特徵
1, 封裝
2, 繼承
3,多型
4, 抽象類
六 ,介面
1, 介面的概念
2,介面的宣告
3, 介面的實現
4,介面中成員變數的特點
5, 介面中成員方法的特點
6, 類和介面的多實現
7, 介面的繼承
8,介面與類的區別:
9, 抽象類和介面的區別
10, 介面中的方法是否可以被過載和覆蓋?
11, 介面的新特性——預設方法和靜態方法(jdk8之後)
12, 標記介面
一、Java 概述
1. Java體系
java是一個體系,包含:
java語言
執行在各種平臺上的虛擬機器
class位元組碼檔案格式
java api(jdk中提供的api),類庫
商業的或者三方優秀開源類庫
- 編寫原始檔
副檔名是.java
- 編譯Java源程式
使用Java編譯器(javac.exe)編譯原始檔,得到位元組碼檔案。
- 執行Java程式
使用JavaSE平臺中的java直譯器(java.exe)來解釋執行位元組碼檔案。
使用Linux(windons)環境編譯執行Java程式
2. 常用的DOS命令
3. JDK、JRE、跨平臺、Java平臺
JDK:它是Java開發執行環境,在程式設計師的電腦上當然要安裝JDK;
JDK = JRE + 開發工具集(例如Javac編譯工具等)
JRE:Java Runtime Environment它是Java執行環境,如果你不需要開發只需要執行Java程式,那麼你可以安裝JRE
JRE = JVM + JavaSE標準類庫
JDK 包含 JRE 包含 JVM
跨平臺特性
平臺指的是作業系統 (Windows,Linux,Mac)。
Java程式可以在任意作業系統上執行,一次編寫到處執行
實現跨平臺需要依賴Java的虛擬機器 JVM (Java Virtual Machine)
為什麼可以跨平臺?因為JAVA程式執行依賴虛擬機器,而針對不同作業系統有不同版本的虛擬機器
Java語言是跨平臺的,Java虛擬機器不是跨平臺的
Java平臺
Java SE (桌面程式)標準版
Java EE (Web程式)企業版
Java ME(移動裝置)微型版 -- Android,IOS興起後就很少使用了
4. Java程式碼的編寫執行過程
原始檔:編寫Java原始檔(我們也稱之為原始碼檔案),它的副檔名為.java;
編譯:然後通過編譯器把原始檔編譯成位元組碼檔案,位元組碼副檔名為.class;
為什麼要編譯?JAVA程式是由虛擬機器執行的,我們所寫的程式碼虛擬機器不認識,我們要把自己寫的程式碼翻譯成虛擬機器所認識的語言
執行:最後使用直譯器來執行位元組碼檔案。
5. 註釋
定義:用來解釋和說明程式的文字,註釋是不會被執行的
分類:
單行註釋: //註釋內容
多行註釋: /註釋內容/
文件註釋: /**註釋內容*/
** 注意:
對於單行和多行註釋,被註釋的文字,不會被JVM解釋執行
對於文件註釋,可以被JDK提供的工具 javadoc 所解析,生成一套以網頁檔案形式體現的該程式的說明文件
單行註釋可以巢狀使用,多行註釋不能巢狀使用
6. 關鍵字、識別符號
-
- 關鍵字
定義:是被Java語言賦予特殊含義,具有專門用途的單詞,比如之前接觸的class,int,double均為Java已經預設好的
特點:字母全部小寫, 注意String不是關鍵字
注意事項:goto 與 const 是Java中的保留字,即沒有賦予特殊含義卻仍被Java佔用的單詞
識別符號
定義:就是給類,介面,方法,變數等起名字時使用的字元序列
組成規則(只能包含下面的內容,不能有其它內容):
英文大小寫字母
數字字元
$和_
- 關鍵字
-
- 注意事項:
數字不能開頭
不可以使用關鍵字
嚴格區分大小寫,不限制長度
起名時,儘量達到見名知意
識別符號中常見的命名規則(這些規定是不受語法約束的):
包名:多單片語成時所有字母均小寫,使用.連線,域名反寫 aaa.bbb.ccc
類名&介面名:大駝峰式 Aaa AaaBbbCcc
變數名&方法名:小駝峰式 aaa aaaBbbCcc
常量名:多單片語成是所有字母均大寫,使用_連線 AAA_BBB_CCC
- 注意事項:
7. Java中的資料型別
- 為什麼有資料型別?
Java語言是強型別語言,對於每一種資料都定義了明確的具體資料型別
Java中資料型別的分類
基本資料型別: 基本資料型別是Java語言中內建的型別,分別是整數型別、小數型別、字元型別、布林型別。這四類基本型別是最簡單、最基礎的型別。
引用資料型別: 是強大的資料型別,它是基於基本資料型別建立的。
JavaSE中提供了一個超級類庫,類庫中包含了近萬種引用資料型別。
基本型別:類 介面 陣列 列舉
8. Java中的常量
定義:常量就是不變的資料量, 在程式執行的過程中其值不可以發生改變
整形常量預設是 int型別
在Java中,定義長整形資料如果值超過int取值範圍後面要+L,否則是錯誤的
小數常量預設是 double型別
D字尾為double,F字尾為float
定義float型別的資料後面要 + f ,否則預設是double
- 常量分類:
整數型別
十進位制表示方式:正常數字。 如 13、25等
二進位制表示方式:以 0b(0B) 開頭。 如0b1011 、0B1001
十六進位制表示方式:以 0x(0X) 開頭。 數字以0-9及A-F組成 如0x23A2、0xa、0x10
八進位制表示方式:以 0 開頭。 如01、07、0721
小數型別:如1.0、-3.15、3.168等
布林型別:true、false ,注意嚴格區分大小寫 - 字元型別:
如 'a','A', '0', '家'
字元必須使用 '' 包裹,並且其中只能且僅能包含一個字元 - 字串型別:
字串String型別是一種引用型別,我們先了解作為常量型別的使用方式
如 "我愛Java","0123","","null"
字串必須使用 "" 包裹,任意長度
在計算機內,有符號數有3種表示法:原碼、反碼和補碼。所有資料的運算都是採用 補碼 進行的
原碼: +8: 0 000 1000 -8: 1 000 1000
就是二進位制定點表示法,即最高位為符號位,0表示正,1表示負,其餘位表示數值的大小。
反碼: +8: 0 000 1000 -8: 1111 0111
正數的反碼與其原碼相同;負數的反碼是對其原碼逐位取反,但符號位除外。
補碼: +8: 0 000 1000 -8: 1111 1000
正數的補碼與其原碼相同;負數的補碼是在其反碼的末位加 1
二、變數和運算子
1. 變數和計算機儲存單元
變數是記憶體中裝載資料的小盒子,你只能用它來存資料和取資料
變數名是識別符號,這說明只要是合法的識別符號都可以用來做變數名。
變數使用的注意事項
變數定義後可以不賦值,使用時再賦值。不賦值不能使用
變數使用時有作用域的限制。(區域性變數和全域性變數)
變數不可以重複定義
計算機儲存單元
計算機中儲存和運算的最小單位:一個位元組,也就是1個位元組(byte)
常用儲存單位1B(位元組) = 8bit(位元位)
1KB = 1024B
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TB
2. 資料型別和常量
- 四類八種
byte: 1個位元組 : -128~127 (資料表示範圍)
short: 2個位元組: -32768~32767
int: 4個位元組: -2147483648~2147483648
long: 8個位元組: -263~263-1
float: 4個位元組: -3.403E38~3.403E38
double: 8個位元組: -1.798E308~1.798E308
char: 2個位元組: 表示一個字元,如('a','A','0','家')
boolean: 1個位元組: 只有兩個值true與false
變數必須要有明確的型別,什麼型別的變數裝載什麼型別的資料
資料類型範圍從小到大排序:
byte < char < short < int < long < float < double,
布林型別boolean不能參與型別轉換
3. 資料型別轉換
自動型別轉換:表示範圍小的資料型別轉換成範圍大的資料型別,這種方式稱為自動型別轉換
自動型別轉換格式:範圍大的資料型別 變數 = 範圍小的資料型別值;
預設轉換:byte、short、char —> int —> long —> float —> double
byte、short、char 相互之間不轉換,他們參與運算首先轉換為 int型別
強制型別轉換:表示範圍大的資料型別轉換成範圍小的資料型別,這種方式稱為強制型別轉換
強制型別轉換格式:範圍小的資料型別 變數 = (範圍小的資料型別) 範圍大的資料型別值;
4. 運算子 和 優先順序
- 算數運算子
-
-
- / % ++ --
-
+: 正號、加、連線字串
++,--運算子後置時,先使用變數a原有值參與運算操作,運算操作完成後,變數a的值自增1或者自減1;
++,--運算子前置時,先將變數a的值自增1或者自減1,然後使用更新後的新值參與運算操作。
-
- 注意事項:
加法運算子在連線字串時要注意,只有直接與字串相加才會轉成字串。
除法當兩邊為整數時,取整數部分,舍餘數。當其中一邊為浮點型時,按正常規則相除。
% 為整除取餘符號,小數取餘沒有意義。結果符號與被取餘符號相同。
整數做被除數,0不能做除數,否則報錯。
小數做被除數,整除 0 結果為 Infinity,對 0 取模結果為 NaN
- 注意事項:
- 賦值運算子
+= -= *= /= %=
+=, -=, *=, /=這樣的賦值運算子包含了一個 強制轉換 的操作,會將左右兩邊運算後的結果,強制型別轉換後賦值給左邊
** 注意:賦值運算子左邊必須是變數
int n = 10;
byte by = 20;
by += n; // 運算完畢後,by的值為byte型別30, 相當於程式碼 by = (byte)(by + n);
- 比較運算子
== != < > <= >=
結果只能是true 和 false
字元間的比較,比較的是其 ASCII 值
浮點數 與 整數 比較,只要值相等,就返回 true
- 邏輯運算子
&與-----false&true-----False
|或-----false|true-----True
異或-----trueflase-----True
!非-----!true-----Flase
&&短路與-----false&&true-----False
||短路或-----false||true-----True
&& : 又叫短路運算子,A&&B,如果A為假,不會去計算B的值,直接得到結果為 false
& : A & B,即使A為假,也會計算B的值。
|| : 也是短路運算子,A || B,如果A為真,不會去計算B的值,直接得到結果為 true
| : A | B,即使A為真,也會計算 B 的值。
異或^ : 左右兩邊條件結果相同,結果就為false,左右兩邊條件結果不同,結果就為true;
- 三目運算子
語法:布林表示式 ? 表示式1 : 表示式2
當布林表示式的值為true,則返回表示式1的值,否則返回表示式2的值
運算子優先順序
-
優先順序 描述 運算子
1 括號 ()、[]
2 正負號 +、-
3 自增自減,非 ++、--、!
4 乘除,取餘 、/、%
5 加減 +、-
6 移位運算 <<、>>、>>>
7 大小關係 >、>=、<、<=
8 相等關係 ==、!=
9 按位與 &
10 按位異或 ^
11 按位或 |
12 邏輯與 &&
13 邏輯或 ||
14 條件運算 ?:
15 賦值運算 =、+=、-=、=、/=、%=
16 位賦值運算 &=、|=、<<=、>>=、>>>= -
位運算子
位運算子
位運算是直接對 二進位制 進行運算
在位運算中,運算元必須是 整型
位異或運算子的特點:
一個數據對另一個數據位異或兩次,該數本身不變。
任何數和自身異或,結果為0
任何數和0異或,結果為本身
<< 左移一位,相當於乘以2: 3 << 2 = 12 --> 322=12
右移一位,相當於除以2: 3 >> 1 = 1 --> 3/2=1
3 >>> 1 = 1 --> 3/2=1
同樣的運算,位運算的效率高於算術運算
三、引用資料型別、流程控制語句 和 陣列
1. 引用資料型別
引用資料型別的變數定義及賦值格式:資料型別 變數名 = new 資料型別();
呼叫該型別例項的功能:變數名.方法名();
-
Scanner類:
導包:import java.util.Scanner;
建立物件例項:Scanner sc = new Scanner(System.in); -
呼叫方法:
int i = sc.nextInt(); //用來接收控制檯錄入的數字
String s = sc.next(); //用來接收控制檯錄入的字串
隨機數類Random -
方法簡介
public int nextInt(int maxValue) //產生 [0,maxValue) 範圍的隨機整數,包含0,不包含maxValue;
public double nextDouble() //產生 [0,1) 範圍的隨機小數,包含0.0,不包含1.0。 -
Random使用方式:
-
import導包:import java.util.Random
建立例項格式:Random 變數名 = new Random();
賦值:a = 變數名.nextInt(maxValue);
2. 流程控制語句
- if
- if...else...
- if...else if...else...
- while
- for
- do...while...
- switch case default break
- case 穿透性:如果多個case條件後面的執行語句是一樣的,則該執行語句只需書寫一次即可,這是一種簡寫的方式
- break語句
作用:跳出所在的迴圈體
使用方式
無法單獨使用,必須將break關鍵字置於 switch 或 迴圈語句 中
執行規律
不需要判斷任何條件,只要遇到break變直接跳出執行後續程式碼。會完全跳出選擇或者迴圈結構
只能跳出 最近的 程式碼塊,不能跨越多級程式碼塊
標記
當break語句出現在巢狀迴圈中的內層迴圈時,它只能跳出內層迴圈,如果想使用break語句跳出外層迴圈則需要對外層迴圈新增標記
使用方式:在外層迴圈外的某行前邊使用,後邊跟有冒號:的識別符號,即定義完畢。
使用時當在內層迴圈使用 break 或 continue 時後邊緊跟之前定義的標號即可
for (j = 1; j <= i; j++) { // 內層迴圈
if (i > 4) { // 判斷i的值是否大於4
break itcast; // 跳出外層迴圈
}
}
- continue語句
作用:提前結束本次迴圈,繼續進行下次迴圈
使用方式: 無法單獨使用,必須將continue關鍵字置於 迴圈語句 中
執行規律: 不需要判斷任何條件,只要遇到continue變直接跳出本輪迴圈進行下次迴圈
return 、break、continue 跳出控制語句的區別
break:結束當前整個迴圈,執行當前迴圈下邊的語句。
continue:結束本次迴圈,繼續進行下次迴圈
return: 用於結束一個方法,返回給上層呼叫者,如果位於main方法內,相當於結束了程式。
return也可以用於結束迴圈,因為return用於結束一個方法,如果方法中有迴圈的話,不管return巢狀於多少層迴圈之內,迴圈都結束。
不會再執行迴圈後面的語句
3. 陣列
- 一維陣列
概述:長度不可變、元素型別相同
一組資料的集合,陣列中的每個資料被稱作'元素'
在陣列中可以存放'任意型別'的元素
但'同一個陣列'裡存放的元素型別必須一致。
陣列是'恆定, 定長的 - 陣列的定義1
格式: 資料型別[] 陣列名 = new 資料型別[長度]; int[] x = new int[100];
使用屬性:陣列名.length
陣列的最小索引是 0, 最大索引是 陣列.length-1 - 陣列的定義2
陣列初始化:在定義陣列時只指定陣列的長度,由系統自動為元素 賦初值 的方式稱作動態初始化。 - 格式:
資料型別[] 陣列名 = new 型別[長度]; int[] arr = new int[4];
型別[] 陣列名 = new 型別[]{元素,元素,……}; int[] arr = new int[]{1,2,3,4};
型別[] 陣列名 = {元素,元素,元素,……}; int[] arr = { 1, 2, 3, 4 };
JVM記憶體劃分 - 暫存器:記憶體和CUP之間
本地方法棧: JVM呼叫了系統中的功能
方法和資料共享: 執行時期class檔案進入的地方
方法棧:所有的方法執行的時候進入記憶體
堆:儲存的是容器和物件
陣列中常見的異常
陣列的索引越界異常
空指標異常 - 二維陣列
定義格式 - 第一種定義格式
相當於定義了一個3*4的二維陣列,即二維陣列的長度為3,二維陣列中的每個元素又是一個長度為4的陣列
- int[][] arr = new int[3][4];//不推薦
-
第二種定義格式
第二種方式和第一種類似,只是陣列中每個元素的長度不確定,必須要new:arr[0] = new int[5];...
int[][] arr = new int[3][]; -
第三種定義格式
二維陣列中定義了三個元素,這三個元素都是陣列,分別為{1,2}、{3,4,5,6}、{7,8,9}
int[][] arr = {{1,2},{3,4,5,6},{7,8,9}};
二維陣列記憶體 -
- 比如:int[][] arr = new int[3][2];
外層陣列長在記憶體開闢連續的3個大的記憶體空間,每一個記憶體空間都對應的有地址值
每一個大記憶體空間裡又開闢連續的兩個小的記憶體空間.
列印陣列
列印一維陣列五種方法
- 比如:int[][] arr = new int[3][2];
Arrays.toString(arr)
for(int n: arr)
System.out.println(n+", ");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ", ");
}
System.out.println(Arrays.asList(arr));
Arrays.asList(arr).stream().forEach(s -> System.out.println(s));//java8
//列印二維陣列三種
for(int i=0;i<arr.length;i++) {
for(int j=0;j<arr[i].length;j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println(); //換行
}
for(int[] a:arr) {
for(int b:a){
System.out.print(b+" ");
}
System.out.println();//換行
}
for(int i=0;i<arr.length;i++)
System.out.println(Arrays.toString(arr[i]));
//列印三維陣列三種``
int [][][] arrays=new int[4][3][2];//在棧空間建立一個空間
for(int i=0;i<arrays.length;i++) {
for(int i1=0;i1<arrays[i].length;i1++) {
for(int i2=0;i2<arrays[i][i1].length;i2++) {
System.out.print(arrays[i][i1][i2]);
}
System.out.println();//二維換行
}
System.out.println();//三維換行
}
四、方法
1. 引入
為什麼要有方法:提高程式碼的複用性
什麼是方法:完成特定功能的程式碼塊
2. 語法格式
訪問修飾符:方法允許被訪問的許可權範圍。( public,protected,private,無修飾符 )
返回型別:void、任何資料型別
方法名:同變數名規則。小寫;多個單詞,第一個單詞首字母小寫,其餘首字母大寫 。myMethod
引數列表:可以省略。引數型別 + 引數名,...
3. 方法呼叫
可以使用 物件名 呼叫方法,靜態方法是使用 類名 呼叫的
方法包括在類中,呼叫時先建立包含方法的類的物件,然後用物件再去呼叫方法。
建立物件:類名 物件名 = new 類名();
呼叫:物件名.方法名();
4. 注意事項
方法引數是 基本型別 ,傳遞的是值。(包含String型別),形式引數的改變對實際引數不影響
方法引數是 引用型別,傳遞的是記憶體地址值。(String型別除外),形式引數的改變對實際引數有影響
方法的定義只能放在類裡面,不能巢狀定義。故而不能在主方法內直接定義方法
方法返回值是void,方法中可以省略return
方法一般在主方法的前面定義
呼叫方法的時候,返回值是void, 不能寫在輸出語句中
5. 方法過載
方法的過載:在同一個類中,方法名相同,引數列表不同。與返回值型別無關。
引數列表不同:
引數個數不同
引數型別不同
引數的順序不同(算過載,但是在開發中不用),注意:必須是不同資料型別。相同型別不存在順序不同
方法過載注意事項
過載和引數變數名無關
過載和返回值型別無關如void method(int x)與int method(int y)不是方法過載,不能同時存在
過載和修飾符無關
過載看 方法名 和 引數列表
6. 可變引數列表
例:
public void sum(int... n){}
引數列表中如果有兩個以上的引數,可變引數一定在最後
可以將陣列傳遞給可變引數列表
陣列作為引數時,不能將多個值傳遞給陣列的
一個方法的形式引數列表,只能有一個可變引數列表
方法名相同,一個引數是可變引數,一個引數是一維陣列,這兩個方法不是過載,因為 一個可變引數等價於相應型別的一維陣列
就可以對可變引數列表,進行相應的陣列操作,比如求長度
可變引數列表所在的方法,是最後被執行訪問的
方法過載的時候,既可以定義有可變引數的同名方法,也可以定義有確定引數個數的方法,jvm呼叫方法時,會優先呼叫 有確定引數個數 的方法
一、封裝
1. 概述
- 定義:將類的某些資訊隱藏在類的內部,不允許外部程式直接訪問。只能通過該類提供的 特定的方法 來實現對隱藏資訊的操作和訪問,也就是:
要隱藏物件的資訊
同時也要留出訪問的介面
2. 封裝的特點
隱藏類的實現細節,實現了資訊的隱藏及安全性,方便修改和實現
提高了程式的模組化,提高系統獨立性和軟體的可重用性,且易於維護
具體實現是編寫該類的人控制的,讓使用者只能通過事先定製好的 方法 來訪問資料,實現者可以方便地加入控制邏輯,限制對屬性的不合理操作
3. 封裝的實現
- 變數:使用 private 修飾,這就是變數的封裝
- 方法:也是一種封裝,封裝了多條程式碼
- 類: 也是一種封裝,封裝了多個方法
封裝的實現步驟:
封裝的實現
public class Cat {
//成員屬性:
//修改屬性可見性---private 限定只能在當前類內訪問,只能修飾成員變數
private String name;
public Cat() {
}
//建立get/set方法
//在get/set方法當中新增屬性的限定
public void setName(String name) { //set方法一般沒有返回值
this.name = name;
}
public String getName() {
return "我是一隻名叫"+this.name+"的貓咪";
}
public int getMonth() {
return month;
}
public void setMonth(int month) { //對年齡進行限定
if(month<=0)
System.out.println("輸入資訊錯誤,寵物貓的年齡必須大於0");
else
this.month = month;
}
}
二、 繼承
1. 概述
一種類於類之間的關係,使用已存在的類作為基礎建立新類。
使用已存在的類的定義作為基礎建立新類
新類的定義可以增加新的資料或新的功能,也可以用父類的功能,但 不能選擇性地繼承父類,必須繼承父類 所有開放的特徵
使用 extends 關鍵字實現
2. 繼承的邏輯關係
不能為了繼承某個功能而隨意進行繼承操作,必須要符合 “A is a B” 關係
3. 繼承的特點:
子類會自動擁有父類所有 非 private 修飾的屬性和方法
通過 子類物件 既可以呼叫自身的 非 private 修飾的成員,也可以呼叫父類的 非 private 修飾的成員
父類 不可以 訪問子類 特有成員,即使是共有的
繼承的出現提高了程式碼的複用性,提高軟體開發效率。
繼承的出現讓類與類之間產生了關係,提供了多型的前提
4. 繼承的注意事項:
在Java中,類只支援單繼承,不允許多繼承,一個類只能有一個直接父類
多個類可以繼承一個父類:
class B extends A{}
class C extends A{} // 類B和類C都可以繼承類A
在Java中,多層繼承 是可以的,即一個類的父類可以再去繼承另外的父類
class A{}
class B extends A{} // 類B繼承類A,類B是類A的子類
class C extends B{} // 類C繼承類B,類C是類B的子類,同時也是類A的子類
在Java中,子類和父類是一種相對概念,一個類是某個類父類的同時,也可以是另一個類的子類
5. 繼承後子類父類成員變數的特點
子類的物件呼叫成員變數的時候,子類自己有,使用子類,子類自己沒有則呼叫父類
子父類中出現了 同名 的成員變數時,在子類中需要訪問父類中非私有成員變數時,需要使用 super 關鍵字
6. 繼承後子類父類成員方法的特性
子類的物件呼叫方法的時候,子類自己有,使用子類,子類自己沒有呼叫的父類
子類中出現與父類一模一樣的方法時,會出現覆蓋操作,也稱為 override 重寫、複寫或者覆蓋
7. 繼承的初始化順序
父類中有:靜態程式碼塊,構造程式碼塊,無參構造方法,靜態屬性。
子類中有:靜態屬性,靜態程式碼塊,構造程式碼塊,無參構造方法
- 執行順序:
- 父類的靜態程式碼塊
- 子類的靜態程式碼塊
- 父類的構造程式碼塊
- 父類的無參構造方法
- 子類的構造程式碼塊
- 子類的無參構造方法
8. 方法過載和方法覆蓋
- 方法過載:
- 同一個類中
- 方法名:過載的兩個方法的方法名必須相同
- 引數列表: 不同,三者至少滿足一個(引數順序、個數、型別),三者至少滿足一個
- 過載與返回值型別、許可權修飾符 無關
- 與方法的引數名 無關
- 方法覆蓋
- 有繼承關係的 子類 中, 子類覆蓋父類的方法
- 方法名:子類方法和父類方法 必須相同,
- 引數列表:子類方法和父類方法的形參列表 必須相同
- 訪問修飾符:子類方法的許可權 >= 父類的方法的許可權
- 返回值型別:
- 基本資料型別: 必須相同
- 引用資料型別:相同 或者 子類方法的返回值型別是父類方法的返回值型別的 子類
- 注意:
當子類重寫父類方法後,子類物件呼叫的是 覆蓋後 的方法。
屬性名也是一樣的道理,沒有重名之前,呼叫的是父類的,重名之後用的是子類的
被 final 修飾的方法不允許在子類中覆蓋
父類被覆蓋的方法的引數列表中被宣告為 final 的引數,在子類的覆蓋方法的中可以不必指定為 final
子類覆蓋方法宣告的 異常列表中的異常類 必須與父類被覆蓋方法宣告的異常列表中的異常類 相容
只有在 子類類體中可以訪問 的父類或祖先類的方法才能被覆蓋
靜態方法 不能被覆蓋,只能被隱藏
如果通過子類物件訪問父類方法,在 父類類體 中,訪問到的任然是子類中的覆蓋方法
三、 多型
1. 概述
- 定義:多種形態,是面嚮物件語言最核心特徵,封裝和繼承都是為多型準備的,非常重要
Java中多型的 程式碼體現 在一個子類物件(實現類物件)既可以給這個子類(實現類物件)引用變數賦值,又可以給這個子類(實現類物件)的父類(介面)變數賦值。
最終多型體現為 父類引用變數可以指向子類物件
如 Student 類可以為 Person 類的子類。那麼一個S tudent 物件既可以賦值給一個 Student 型別的引用,也可以賦值給一個 Person 型別的引用。 - 多型的分類:
Java中的多型一般是執行時多型 - 編譯時多型:設計時多型,方法過載來實現
- 執行時多型:程式執行時動態決定呼叫哪個方法
- 多型的前提:必須有 子父類關係 或者類 實現介面關係,否則無法完成多型。
- 多型的優點:
提高程式碼的可維護行
提高程式碼的擴充套件性
多型的弊端:不能使用子類的特有功能
如何解決?
法1:建立子類物件呼叫子類方法
法2:把父類的引用強轉為子類引用
2. 多型呼叫的三種格式
父類的引用變數指向子類物件:父類型別 變數名 = new 子類型別();
普通類多型定義的格式:父類 變數名 = new 子類();
抽象類多型定義格式:抽象類 變數名 = new 抽象類子類();
介面多型定義的格式:介面 變數名 = new 介面實現類();
3. 注意事項:
同一個父類的方法會被不同的子類重寫。在呼叫方法時,呼叫的為各個 子類覆蓋後的方法
Person p1 = new Student();
Person p2 = new Teacher();
p1.work(); //p1會呼叫Student類中重寫的work方法
p2.work(); //p2會呼叫Teacher類中重寫的work方法
當變數名指向不同的子類物件時,由於每個子類覆蓋父類方法的內容不同,所以會呼叫不同的方法。
4. 多型中成員訪問的特點
成員變數
編譯看左邊(引用變數的宣告型別),執行看左邊(實際訪問到的成員變數的值,也是由引用變數的宣告型別來決定)
方法
編譯看左邊(引用變數的宣告型別),執行看右邊(實際訪問到的方法,是由引用變數所指向的物件的實際型別來決定)
5. 編譯時多型(方法過載 overload)
因為對於方法過載而言,雖然多個方法的方法名相同,但是我們的編譯器,可以根據方法呼叫程式碼推斷出,所要呼叫的那個方法的方法簽名,從而根據方法簽名(jvm唯一的),確定要呼叫的方法
- 注:方法簽名: 方法名+方法引數列表**
6. 執行時多型
因為在編譯器編譯的時候,無法知道,具體呼叫的是哪個方法的程式碼,只有當 jvm 具體真正執行到呼叫程式碼的地方,jvm才能知道呼叫的究竟是哪個方法
實現執行時多型:繼承、方法覆蓋/重寫(override)、父類引用指向子類物件
7. 多型的轉型
- 向上轉型:當有 子類物件賦值給一個父類引用 時,便是向上轉型,多型本身就是向上轉型的過程。(也叫:隱式轉型、自動轉型)
格式:父類型別 變數名 = new 子類型別();
向下轉型:一個 已經向上轉型 的子類物件可以使用 強制型別轉換 的格式,將父類引用轉為子類引用,這個過程是向下轉型。如果是直接建立父類物件,是無法向下轉型的! - 格式:子類型別 變數名 = (子類型別) 父類型別的變數;
什麼時候使用向上轉型?
當不需要面對子類型別時,通過提高擴充套件性,或者使用父類的功能就能完成相應的操作,這時就可以使用向上轉型。
什麼時候使用向下轉型?
當要使用子類特有功能時,就需要使用向下轉型。 - 向下轉型的好處:可以使用子類特有功能。
但是弊端是需要面對具體的子類物件;在向下轉型時容易發生 ClassCastException 型別轉換異常。在轉換之前必須做 型別判斷
如:
if( !a instanceof Dog){…}
8. instanceof 關鍵字
- 作用: 可以通過 instanceof 關鍵字來判斷是否能夠物件轉化。也就是,一個引用型的變數,是不是這個型別的物件,提高向下轉型的安全性
- 格式: boolean b = 物件 instanceof 資料型別; ,返回 true / false
- 注意:null instanceof <類名> 結果永遠是 false
Person p1 = new Student(); // 前提條件,學生類已經繼承了人類
boolean flag = p1 instanceof Student; //flag結果為true
boolean flag2 = p2 instanceof Teacher; //flag結果為false
四、 抽象類
1. 概述
在Java中,一個沒有方法體的方法應該定義為抽象方法,而如果一個類中含有抽象方法,則該類必須定義為一個抽象類
抽象類通常作為一個 框架(雖然在父類抽象類中,有些行為並不能具體確定,但是從類設計的角度將,我們能確定該類存在這樣的行為),把子類將實現的抽象方法組織起來,簡化或限制子類的設計
2. 抽象類的定義格式
- 抽象方法定義的格式:
public abstract 返回值型別 方法名(引數);
- 抽象類定義的格式:
abstract class 類名 {}
3. 抽象類特點
抽象類和抽象方法都需要被 abstract 修飾。抽象方法一定要定義在抽象類中。
static、final、private 不能與 abstract 同時出現。
抽象方法 不能有 方法體
抽象類 不一定 有抽象方法,但是含有抽象方法的類 必須是 抽象類
構造方法,類方法(用 static 修飾的方法),不能宣告為抽象方法。
抽象類本身不能例項化(但是多型機制可以用子類例項化),不可以直接建立物件
原因:呼叫抽象方法沒有意義
只有覆蓋了抽象類中 所有的 抽象方法後,其子類才可以建立物件。否則該子類還是一個抽象類。
抽象類只定義了類的部分行為(包含具體行為), 這些行為是 子類共有的,其它行為由子類實現的抽象方法提供
4. 抽象類成員特點
抽象類的 成員變數:既可以變數,又可以是常量
抽象類的 構造方法:用於父類資料的初始化
子類繼承抽象類時,構造方法不會被覆蓋。 而且,在例項化子類物件時首先呼叫的是抽象類中的構造方法再呼叫子類中的。
因此,在抽象類中可以使用構造方法封裝,所繼承子類公共的東西。
抽象類的 方法:可以是抽象的,也可以是非抽象的,
- 作用:
抽象的:強制子類實現 (語法上的強制約束力)
非抽象的:子類可以複用
5.抽象類的子類(二選一)
如果不想重寫抽象類裡面的抽象方法,則子類也必須是抽象類
如果不是抽象類,則必須實現抽象父類的所有抽象方法
6. 抽象類的細節
抽象類一定是個父類?
嚴格來說是的,不是父類的話就沒有意義了,抽象類的抽象方法必須由子類來實現 本身只起到定義的作用
抽象類中是否可以沒有抽象方法?如果可以,那麼,該類還定義成抽象類有意義嗎?為什麼?
可以沒有抽象方法,有意義,是為了不讓該類建立物件,方法可以直接讓子類去使用
在實際開發中,有的時候,不希望使用者,直接例項化出一個類的物件,可以將這個類定義為 abstract
五,介面
1、 介面的概念
介面是功能的集合,同樣可看做是一種特殊的資料型別,是比抽象類更為抽象的類。
介面只描述所應該具備的方法,並沒有具體實現,具體的實現由介面的實現類(相當於介面的子類)來完成。這樣將功能的定義與實現分離,優化了程式設計。
記住:一切事物均有功能,即一切事物均有介面
2、 介面的宣告
使用 interface 代替了原來的 class 其他步驟與定義類相同
public interface 介面名稱 extends 其他的類/介面名 {
//宣告變數
//抽象方法
}
介面是隱式抽象的,當宣告一個介面的時候,不必使用abstract關鍵字。
3、介面的實現
當類實現介面的時候,類要實現介面中所有的方法。否則,類必須宣告為抽象類。
類使用implements關鍵字實現介面.
一個類如果實現介面, 有兩種操作方法:
實現類為非抽象類, 就需要重寫介面中所有的抽象方法.
實現類為抽象類, 可以不重寫介面中的抽象方法。
class 類 implements 介面1,介面2... {
//重寫介面中方法
}
四、 介面中成員變數的特點
介面中無法定義普通的成員變數.
介面中定義的變數,必須有固定的修飾符修飾public static final ,所以介面中的變數也稱之為常量,其值不能改變。
static 可以被類名、介面名直接呼叫
final 最終,固定住變數的值
public static final 在介面中可以省略不寫,也可以選擇性寫,但是不代表沒有.
介面中的成員變數必須顯式初始化.
interface Demo { ///定義一個名稱為Demo的介面。
public static final int NUM = 3;// NUM的值不能改變
}
5、 介面中成員方法的特點
介面中的成員都是 public 的,不能指定其它的訪問控制修飾符
介面中成員方法定義的固定格式: public abstract 返回值型別 方法名字(引數列表)
子類必須覆蓋介面中所有的抽象方法後,子類才可以例項化,否則子類是一個抽象類。
6、 類和介面的多實現
類和介面的多實現是介面最重要的體現:解決多繼承的弊端。將多繼承這種機制在 java 中通過多實現完成了。
多繼承的弊端:
多繼承時,當多個父類中有相同功能時,子類呼叫會產生不確定性。
其實核心原因就是在於多繼承父類中功能有主體,而導致呼叫執行時,不確定執行哪個主體內容。
為什麼多實現能解決? 因為介面中的功能都沒有方法體,都是由子類/實現類重寫來明確
7、 介面的繼承
一個介面能繼承另一個介面,和類之間的繼承方式比較相似。介面的繼承使用extends關鍵字,子介面繼承父介面的方法。
在Java中,類的多繼承是不合法,但介面允許多繼承。
8、 介面與類的區別:
介面不能用於例項化物件。
介面沒有構造方法。
介面中所有的方法必須是抽象方法。
介面不能包含普通成員變數,除了 static 和 final 變數。
介面不是被類繼承了,而是要被類實現。
介面支援多繼承。
9、 抽象類和介面的區別
相同點
抽象類和介面都位於繼承的頂端,用於被其他類實現或繼承.
都不能直接例項化物件.
都包含抽象方法,其子類都必須覆蓋這些抽象方法.
區別
抽象類中的方法可以有方法體,就是能實現方法的具體功能,但是介面中的方法不行。
抽象類中的成員變數可以是各種型別的,而介面中的成員變數只能是 public static final型別的。
介面中不能含有靜態程式碼塊以及靜態方法(用 static 修飾的方法),而抽象類是可以有靜態程式碼塊和靜態方法。
一個類只能繼承一個抽象類,而一個類卻可以實現多個介面。
二者的選擇:
優先選用介面,儘量少用抽象類;
需要定義子類的行為,又要為子類提供共性功能時才選用抽象類;
10、 介面中的方法是否可以被過載和覆蓋?
過載: 對於介面中的方法過載,過載條件和普通類沒有任何區別,只是過載的方法沒有方法體
覆蓋: 介面中的方法也可以覆蓋(Override),但沒有實際的意義,因為介面中不提供方法的實現
11、介面的新特性——預設方法和靜態方法(jdk8之後)
預設方法
可以在不影響已有類的情況下,修改介面
可以有方法實現
父類中的預設方法可以被子介面繼承
子介面可以覆蓋父介面中的預設方法,甚至還可以把父介面中的預設方法覆蓋為抽象方法
實現介面後,因為預設方法不是抽象方法,所以可以不重寫,但是如果開發需要,也可以重寫
預設方法使用default 關鍵字,只能通過介面實現類的物件來呼叫。
注意:預設方法的訪問許可權也是預設public
靜態方法
可以有方法實現
可以直接通過介面名來訪問
靜態方法沒有方法覆蓋,因為靜態方法沒有執行時多型
interface Test{
//這個是預設方法
default String get(String aa){
System.out.println("我是jdk1.8預設實現方法...");
return "";
}
//這個是靜態方法
static void staticmethod(){
System.out.println("我是靜態方法");
}
}
注意事項
介面預設方法、靜態方法可以有多個。
預設方法通過例項呼叫,靜態方法通過介面名呼叫。
default 預設方法關鍵字只能用在介面中。
預設方法可以被繼承,如果繼承了多個介面,多個介面都定義了多個同樣的預設方法,實現類需要重寫預設方法不然會報錯。
靜態方法不能被繼承及覆蓋,所以只被具體所在的介面呼叫。
12、 標記介面
標記介面是沒有任何方法和屬性的介面.
它僅僅表明它的類屬於一個特定的型別,供其他程式碼來測試允許做一些事情。
標記介面作用:簡單形象的說就是給某個物件打個標(蓋個戳),使物件擁有某個或某些特權。
例如:
java.awt.event 包中的 MouseListener 介面繼承的 java.util.EventListener 介面定義如下:
package java.util;
public interface EventListener {
}
標記介面主要用於以下兩種目的:
建立一個公共的父介面:
正如EventListener介面,這是由幾十個其他介面擴充套件的Java API,你可以使用一個標記介面來建立一組介面的父介面。 例如:當一個介面繼承了EventListener介面,Java虛擬機器(JVM)就知道該介面將要被用於一個事件的代理方案。
向一個類新增資料型別:
這種情況是標記介面最初的目的,實現標記介面的類不需要定義任何介面方法(因為標記介面根本就沒有方法),但是該類通過多型性變成一個介面型別。