久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

尚硅谷Java入门视频教程(在线答疑+Java面试真题)

發布時間:2024/3/13 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 尚硅谷Java入门视频教程(在线答疑+Java面试真题) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java核心技術

一、Java基本語法

1、關鍵字與保留字

關鍵字的定義和特點

  • 被Java語言賦予了特殊含義,用做專門用途的字符串(單詞)
  • 關鍵字中所有字母都為小寫

保留字的定義

  • 現有Java版本尚未使用,但以后版本可能會作為關鍵字使用。命名標識符時要避免使用這些保留字。

總結:48個關鍵字、2個保留字、3個字面值

用于定義數據類型的關鍵字 class interface enum byte short int long float double char boolean void 用于定義流程控制的關鍵字 if else switch case default while do for break continue return 用于定義訪問權限修飾符的關鍵字 private protected public 用于定義類,函數,變量修飾符的關鍵字 abstract final static synchronized 用于定義類與類之間關系的關鍵字 extends implements 用于定義建立實例及引用實例,判斷實例的關鍵字 new this super instanceof 用于異常處理的關鍵字 try catch finally throw throws 用于包的關鍵字 package import 其他修飾符關鍵字 native strictfp transient volatile assert保留字 goto const用于定義數據類型值的字面值 true false null

2、標識符

標識符的定義

  • Java對各種變量、方法和類等要素命名時使用的字符序列稱為標識符

技巧:凡是自己可以起名字的地方都叫標識符

定義合法標識符規則

  • 由26個英文字母大小寫,0-9,_或$組成
  • 數字不可以開頭
  • 不可以使用關鍵字和保留字,但能包含關鍵字和保留字
  • Java中嚴格區分大小寫,長度無限制
  • 標識符不能包含空格

Java中的名稱命名規范

  • 包名:多單詞組成時所有字母都小寫:xxxyyyzzz
  • 類名、接口名:多單詞組成時,所有單詞的首字母大寫:XxxYyyZzz
  • 變量名、方法名:多單詞組成時,第一個單詞首字母小寫,第二個單詞開始每個單詞首字母大寫:xxxYyyZzz
  • 常量名:所有字母都大寫,多單詞時每個單詞用下劃線連接:XXX_YYY_ZZZ

注意點:
1、在起名字時,為了提高閱讀性,要盡量有意義,“見名知意”。
2、Java采用unicode字符集,因此標識符也可以使用漢字聲明,但是不建議使用。

3、變量

變量的概念

  • 內存中的一個存儲區域
  • 該區域的數據可以在同一類型范圍內不斷變化
  • 變量是程序中最基本的存儲單元,包含變量類型、變量名存儲的值

變量的作用

  • 用于在內存中保存數據

使用變量注意

  • Java中每個變量必須先聲明,后使用
  • 使用變量名來訪問這塊區域的數據
  • 變量的作用域:其定義所在的一對{}內
  • 變量只有在其作用域內才有效
  • 同一個作用域內,不能定義重名的變量

變量的分類

按數據類型分類

  • 基本數據類型
    • 數值型
      • 整數類型 (byte short int long)
      • 浮點類型 (float double)
    • 字符型 (char)
    • 布爾型 (boolean)
  • 引用數據類型
    • (class)
    • 接口 (interface)
    • 數組 ([])

按聲明位置分類

  • 成員變量
    • 實例變量 (不以static修飾)
    • 類變量 (以static修飾)
  • 局部變量
    • 形參 (方法、構造器中定義的變量)
    • 方法局部變量 (在方法內部定義)
    • 代碼塊局部變量 (在代碼塊內定義)

整數變量:byte、short、int、long

  • Java各整數類型有固定的表數范圍和字段長度,不受具體OS的影響,以保證Java程序的可移植性。
  • Java的整型常量默認為int型,聲明long型常量須加l或者L
  • Java程序中變量通常聲明為int型,除非不足以表示較大的數,才使用long
類型占用存儲空間表數范圍
byte1字節=8bit位-128~127
short2字節- 2 15 2^{15} 215~ 2 15 2^{15} 215-1
int4字節- 2 31 2^{31} 231~ 2 31 2^{31} 231-1(約21億)
long8字節- 2 63 2^{63} 263~ 2 63 2^{63} 263-1

bit:計算機中的最小存儲單位。byte:計算機中基本存儲單元。

浮點類型:float、double

  • 與整數類型類似,Java浮點類型也有固定的表數范圍和字段長度,不受具體操作系統的影響
  • 浮點型常量有兩種表示形式:
    • 十進制數形式
    • 科學計數法形式
  • float:單精度,尾數可以精確到7位有效數字。很多情況下,精度很難滿足需求。
  • double:雙精度,精度是float的兩倍。通常采用此類型。
  • Java的浮點型常量默認是double型,聲明float型常量,須后加f或F。
類型占用存儲空間表數范圍
float4字節-3.403E38~3.403E38
double8字節-1.798E308~1.798E308

注意點:float表示數值的范圍比long還大

字符類型:char

  • char型數據用來表示通常意義上“字符”(2字節)
  • Java中所有字符都使用Unicode編碼,故一個字符可以存儲一個字母,一個漢字,或其他書面語的一個字符。
  • 字符型變量的三種表現形式:
    • 字符常量是用單引號’'括起來的單個字符。
    • Java中還允許使用轉義字符’\'來將其后的字符轉變為特殊字符型常量。
    • 直接使用Unicode值來表示字符型常量。
  • char類型是可以進行運算的。因為它都對應有Unicode編碼。
char c1 = 'a'; // 編譯通過 // char c2 = 'AB'; // 編譯不通過 char c3 = '中'; // 編譯通過 char c4 = '\n'; // 編譯通過 char c5 = '\u0043'; // 編譯通過 // char c6 = ''; // 編譯不通過 char c7 = 97; // a, 開發中極其少見

常用ASCII碼值: ‘a’ == 97; ‘A’ == 65;

布爾型:boolean

  • 只能取兩個值之一:true、false
  • 常常在條件判斷、循環結構中使用

基本數據類型轉換

  • 自動類型轉換:容量小的類型自動轉換為容量大的數據類型。數據類型按容量大小排序為:char、byte、short --> int --> long --> float --> double
  • 有多種類型的數據混合運算時,系統首先自動將所有數據類型轉換為容量最大的那種數據類型,然后再進行計算
  • byte,short,char之間不會互相轉換,他們三者在計算時首先轉換為int類型

Java在做運算的時候,如果操作數均在int范圍內,那么一律在int的空間內運算。

  • boolean類型不能與其它數據類型運算
  • 當把任何基本數據類型的值和字符串(String)進行連接運算時(+),基本數據類型的值將自動轉化為字符串(String)類型

說明:此時的容量大小指的是表示數的范圍的大小。比如:float容量要大于long的容量

強制類型轉換

  • 自動類型轉換的逆過程,將容量大的數據類型轉換為容量小的數據類型。使用時要加上強制轉換符:(),但可能造成精度降低或溢出,格外要注意
double d1 = 12.9;int i1 = (int)d1; // 12,截斷操作int i2 = 128;byte b = (byte)i2; // -128
  • 通常,字符串不能直接轉換為基本類型,但通過基本類型對應的包裝類則可以實現把字符串轉換為基本類型
String a = "43";int i = Integer.parseInt(a);
  • boolean類型不可以轉換為其它的數據類型

說明:整型常量,默認類型是int型;浮點型常量,默認類型是double型。

byte b = 12;// byte b1 = b + 1; // 編譯失敗// float f1 = b + 12.3; // 編譯失敗

字符串類型:String

  • String不是基本數據類型,屬于引用數據類型
  • 使用方式與基本數據類型一致。
  • 一個字符串可以串接另一個字符串,也可以直接串接其他類型的數據。
String str = "abcd";str = str + "xyz";int n = 100;str = str + n; // abcdxyz100

4、進制

  • 所有數字在計算機底層都是以二進制形式存在。
  • 對于整數,有四種表示方式:
    • 二進制(binary):0,1,滿2進1,以0b或0B開頭
    • 十進制(decimal):0-9,滿10進1
    • 八進制(octal):0-7,滿8進1,以數字0開頭表示
    • 十六進制(hex):0-9及A-F,滿16進1,以0x或0X開頭表示。此處的A-F不區分大小寫。
  • Java整數常量默認是int類型,當用二進制定義整數時,其第32位(最高位)是符號位:當是long類型時,二進制默認占64位,第64位是符號位
  • 二進制的整數有如下三種形式:
    • 原碼:直接將一個數值換成二進制數。最高位是符號位
    • 負數的反碼:是對原碼按位取反,只有最高位(符號位)確認為1
    • 負數的補碼:其反碼加1
  • 計算機以二進制補碼的形式保持所有的整數
    • 正數的原碼、反碼、補碼都相同
    • 負數的補碼是其反碼+1

5、運算符

運算符是一種特殊的符號,用以表示數據的運算、賦值和比較等。

  • 算術運算符
  • 賦值運算符
  • 比較運算符(關系運算符)
  • 邏輯運算符
  • 位運算符
  • 三元運算符

算術運算符

運算符運算范例結果
+正號+33
-負號b=4; -b-4
+5+510
-6-42
*3*412
/5/51
%取模(取余)7%52
++自增(前),先運算后取值a=2;b=++a;a=3;b=3
++自增(后),先取值后運算a=2;b=a++;a=3;b=2
自減(前),先運算后取值a=2;b=–a;a=1;b=1
自減(后),先取值后運算a=2;b=a–;a=1;b=2
+字符串連接“He”+“llo”“Hello”

疑難點1:%取余運算,結果的符號與被模數的符號相同

int m1 = 12; int n1 = 5; System.out.println("m1 % n1 = " + m1 % n1); // m1 % n1 = 2 int m2 = -12; int n2 = 5; System.out.println("m1 % n1 = " + m2 % n2); // m1 % n1 = -2 int m3 = 12; int n3 = -5; System.out.println("m1 % n1 = " + m3 % n3); // m1 % n1 = 2 int m4 = -12; int n4 = -5; System.out.println("m1 % n1 = " + m4 % n4); // m1 % n1 = -2

疑難點2:++ 和 – 不會改變變量本身的數據類型

short s = 10; //s = s + 1; //編譯失敗 s = (short) (s + 1); //正確 s++; //正確byte b = 127; b++; System.out.println(b); //-128

賦值運算符

符號:= 拓展賦值運算符:+=,-=,*=,/=,%=

  • 當=兩側數據類型不一致時,可以使用自動類型轉換或使用強制類型轉換原則進行處理
  • 支持連續賦值
int i, j; //連續賦值 i = j = 10;

疑難點:拓展賦值運算符不會改變變量本身的數據類型

short s = 10; //s = s + 2; //編譯失敗 s += 2; System.out.println(s); //12 int i = 1; i *= 0.1; System.out.println(i); // 0

比較運算符

運算符運算范例結果
==相等于4==3false
!=不等于4!=3true
<小于4<3false
>大于4>3true
<=小于等于4<=3false
>=大于等于4>=3true
instanceof檢查是否是類的對象“Hello” instanceof Stringtrue
  • 比較運算符的結果都是boolean型,也就是要么是true,要么是false。
  • 比較運算符==不能誤寫成=
  • > < >= <=:只能使用在數值類型的數據之間
  • ==:不僅可以使用在數值類型數據之間,還可以使用在其他引用類型變量之間。

邏輯運算符

&-邏輯與
|-邏輯或
!-邏輯非
&&-短路與
||-短路或
^-邏輯異或

aba&ba&&ba|ba||b!aa^b
truetruetruetruetruetruefalsefalse
truefalsefalsefalsetruetruefalsetrue
falsetruefalsefalsetruetruetruetrue
falsefalsefalsefalsefalsefalsetruefalse

區分 & 與 &&

  • 相同點1:&與&&的運算結果相同
  • 相同點2:當符號左邊為true時,二者都會執行符號右邊的運算
  • 不同點:當符號左邊為false時,&繼續執行符號右邊的運算,&&不再執行符號右邊的運算

區分 | 與 ||

  • 相同點1:|與||的運算結果相同
  • 相同點2:當符號左邊是false時,二者都會執行符號右邊的運算
  • 不同點1:當符號左邊是true時,|繼續執行符號右邊的運算,而||不再執行符號右邊的運算

位運算符

運算符運算范例
<<左移3 << 2 = 12 --> 3*2*2=12
>>右移3 >> 1 = 1 --> 3/2=1
>>>無符號右移3 >>> 1 = 1 --> 3/2=1
&與運算6 & 3 = 2
|或運算6 | 3 = 7
^異或運算6 ^ 3 = 5
~取反運算~6 = -7

位運算時直接對整數的二進制進行的運算

運算符描述
<<空位補0,被移除的高位丟棄,空缺位補0
>>被移除的二進制最高位是0,右移后,空缺位補0,若最高位是1,空缺位補1
>>>被移位二進制最高位無論是0或者是1,空缺位都用0補
&二進制位進行&運算,只有1&1時結果是1,否則是0
|二進制位進行|運算,只有0|0時結果是0,否則是1
^相同二進制進行^運算結果是0:1^1=0,0^0=0;不相同二進制位^運算結果是1:1^0=1,0^1=1
~各二進制碼按補碼各位取反

m = k ^ n = (m ^ n) ^ n

三元運算符

  • 格式:(條件表達式) ? 表達式1 : 表達式2;
  • 表達式1和表達式2為同種類型

三元運算符與if-else的聯系與區別

  • 三元運算符可簡化if-else語句
  • 三元運算符要求必須返回一個結果
  • if后的代碼塊可有多個語句

附加:運算符的優先級

. () {} ; ,
R–>L++ -- ~ !(data type)
L–>R* / %
L–>R+ -
L–>R<< >> >>>
L–>R< > <= >= instanceof
L–>R== !=
L–>R&
L–>R^
L–>R|
L–>R&&
L–>R||
R–>L? :
R–>L= *= /= %=
+= -= <<= >>=
>>>= &= ^= |=

6、程序流程控制

  • 程序控制語句是用來控制程序中各語句執行順序的語句,可以把語句組合成能完成一定功能的小邏輯模塊。
  • 其流程控制方式采用結構化程序設計中規定的三種基本流程結果,即:順序結構、分支結構、循環結構

分支結構

if-else結構

  • else 結構是可選的
  • 針對與條件表達式:
    • 如果多個條件表達式之間是“互斥”關系(或沒有交集的關系),哪個判斷和執行語句聲明在上面還是下面,無所謂。
    • 如果多個條件表達式之間有交集的關系,需要根據實際情況,考慮清楚應該將哪個結構聲明在上面。
    • 如果多個條件表達式之間有包含關系,通常情況下,需要將范圍小的聲明在范圍大的上面。否則,范圍小的就沒有機會執行
  • if-else 結構是可以互相嵌套的。
  • 如果if-else結構中的執行語句只有一行時,對應的一對{}可以省略的。但是,不建議大家省略。
  • 多個if-else時,if-else的配對方式采用就近原則進行配對

switch-case結構

switch(表達式){case 常量1:語句1;// break;case 常量2:語句2;// break;... ...case 常量N:語句N;// break;default:語句;// break; }
  • 根據switch表達式中的值,依次匹配各個case中的常量。一旦匹配成功,則進入相應的case結構中,調用其執行語句。當調用完執行語句以后,則仍然繼續向下執行其他case結構中的執行語句,直到遇到break關鍵字或此switch-case結構末尾結束為止。
  • break,可以使用在switch-case結構中,表示一旦執行到此關鍵字,就跳出switch-case結構
  • switch結構中的表達式,只能是如下的6種數據類型之一:byte、short、char、int、枚舉類型(JDK5.0新增)、String類型(JDK7.0新增)
  • case 之后只能聲明常量,不能聲明范圍。
  • break 關鍵字是可選的
  • default:相當于if-else結構中的else。default結構是可選的,而且位置是靈活的。
int number = 0; // Console: zero switch(number) {default:System.out.println("other");case 0:System.out.println("zero");break;case 1:System.out.println("one");break; }
  • 凡是可以使用switch-case的結構,都可以轉換為if-else。反之,不成立。
  • 當發現既可以使用switch-case且switch中表達式的取值情況不太多,又可以使用if-else時,我們優先選擇使用switch-case。原因:switch-case執行效率稍高。

循環結構

循環語句的四個組成部分

  • 初始化部分
  • 循環條件部分
  • 循環體部分
  • 迭代部分

for循環結構

for(初始化部分;循環條件部分;迭代部分) {循環體部分 }執行過程:初始化部分-循環條件部分-循環體部分-迭代部分-循環條件部分-循環體部分-迭代部分- ... - 循環條件部分

while循環結構

初始化部分 while(循環條件部分) {循環體部分迭代部分 }執行過程:初始化部分-循環條件部分-循環體部分-迭代部分-循環條件部分-循環體部分-迭代部分- ... - 循環條件部分
  • 寫while循環千萬小心不要丟了迭代條件。一旦丟了,就可能導致死循環!
  • 寫程序需要避免出現死循環。
  • for循環和while循環是可以相互轉換的。區別在于for循環和while循環的初始化條件部分的作用范圍不同。

do-while循環結構

初始化部分 do{循環體部分迭代部分 }while(循環條件部分);執行過程:初始化部分-循環體部分-迭代部分-循環條件部分-循環體部分-迭代部分- ... - 循環條件部分
  • do-while循環至少會執行一次循環體!
  • 開發中,使用for和while更多一些。較少使用do-while

特殊關鍵字的使用

適用范圍不同點相同點
breakswitch-case和循環結構中結束當前循環關鍵字后面不能聲明執行語句
continue循環結構中結束當次循環關鍵字后面不能聲明執行語句
label: for(int i = 1; i <= 4; i++) {for(int j = 1; j <= 10; j++) {if (j % 4 == 0) {//break; //默認跳出包裹此關鍵字最近的一層循環//continue;//break label; //結束指定標識的一層循環結構continue label; //結束指定標識的一層循環結構當次循環}}}
  • return:并非專門用于結束循環的,它的功能是結束一個方法。當一個方法執行到一個return語句時,這個方法將被結束。
  • 與break和continue不同的是,return直接結束整個方法,不管這個return處于多少層循環之內

7、數組

  • 數組(Array),是多個相同類型數據按一定順序排列的集合,并使用一個名字命名,并通過編號的方式對這些數據進行統一管理。
  • 數組本身是引用數據類型,而數組中的元素可以是任何數據類型,包括基本數據類型和引用數據類型。
  • 創建數組對象會在內存中開辟一整塊連續的空間,而數組名中引用的是這塊連續空間的首地址。
  • 數組的長度一旦確定,就不能修改。
//1.一維數組的聲明和初始化 int[] ids;//聲明 //1.1靜態初始化:數組的初始化和數組元素的賦值操作同時進行 ids = new int[]{1001,1002,1003,1004}; //1.2動態初始化:數組的初始化和數組元素的賦值操作分開進行 String[] names = new String[5];

數組元素的默認初始化值

  • 數組元素是整型:0
  • 數組元素是浮點型:0.0
  • 數組元素是char型:0或者’\u0000’,而非’0’
  • 數組元素是boolean型:false
  • 數組元素是引用數據類型:null

對于二維數組的理解:我們可以看成是一維數組array1又作為另一個一維數組array2的元素而存在。其實,從數組底層的運行機制來看,其實沒有多維數組。

//一些錯誤的寫法 //int[] ids; //ids = {1,2,2}; //編譯錯誤 //一些正確但是不標準的寫法 int[] arr1 = {1,2,2,3}; //類型推斷 int[] arr2[] = new int[][]{{1,2,2},{4,5},{6,7,8}}; // 數組[]位置可以隨意 int[] arr3[] = {{1,2,2},{4,5},{6,7,8}}; String[] strArray1[] = {{"222", "2222"},{"111", "3333", "5555"}};

附加:Arrays工具類的使用

  • java.util.Arrays類即為操作數組的工具類,包含了用來操作數組的各種方法
方法作用
boolean equals(int[] a,int[] b)判斷兩個數組是否相等
String toString(int[] a)輸出數組信息
void fill(int[] a,int val)將指定值填充到數組之中
void sort(int[] a)對數組進行排序
int binarySearch(int[] a,int key)對排列后的數組進行二分法檢索指定的值

二、面向對象編程

1、面向過程與面向對象

面向過程(POP)與面向對象(OOP)

  • 二者都是一種思想,面向對象是相對于面向過程而言的。面向過程,強調的是功能行為,以函數為最小單位,考慮怎么做。面向對象,將功能封裝進對象,強調具備了功能的對象,以類/對象為最小單位,考慮誰來做。
  • 面向對象更加強調運用人類在日常的思維邏輯中采用的思想方法與原則,如抽象、分類、繼承、聚合、多態等。

面向對象的三大特征

  • 封裝性
  • 繼承性
  • 多態性

面向對象的思想概述

  • 程序員從面向過程的執行者轉化成了面向對象的指揮者
  • 面向對象分析方法分析問題的思路和步驟:
    • 根據問題需要,選擇問題所針對的現實世界的實體
    • 從實體中尋找解決問題相關的屬性和功能,這些屬性和功能就形成了概念世界中的類
    • 把抽象的實體用計算機語言進行描述,形成計算機世界中的類的定義。即借助某種程序語言,把類構造成計算機能夠識別和處理的數據結構。
    • 類實例化成計算機世界中的對象。對象是計算機世界中解決問題的最終工具。

2、Java語言基本元素:類和對象

類和對象

  • 類(Class)和對象(Object)是面向對象的核心概念。
    • 類是對一類事物的描述,是抽象的、概念上的定義
    • 對象是實際存在的的該類事物的每個個體,因而也稱為實例

類和對象的使用(面向對象思想落地的實現)

  • 創建類,設計類的成員
  • 創建類的對象
  • 通過"對象.屬性"或"對象.方法"調用對象的結構

如果創建了一個類的多個對象,則每個對象都獨立的擁有一套類的(非static的)屬性。意味著:如果我們修改一個對象的屬性a,則不影響另外一個對象屬性a的值。

對象的創建和使用:內存解析

  • 堆(Heap),此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存。這一點在Java虛擬機規范中的描述是:所有的對象實例以及數組都要在堆上分配。
  • 通常所說的棧(Stack),是指虛擬機棧。虛擬機棧用于存儲局部變量等。局部變量表存放了編譯期可知長度的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型,它不等同于對象本身,是對象在堆內存的首地址)。方法執行完,自動釋放。
  • 方法區(Method Area),用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據

3、類的成員之一:屬性

屬性(成員變量) VS 局部變量

  • 相同點
    • 定義變量的格式:數據類型 變量名 = 變量值
    • 先聲明,后使用
    • 變量都有其對應的作用域
  • 不同點
    • 在類中聲明的位置不同。屬性直接定義在類的一對{}內;局部變量聲明在方法內、方法形參、代碼塊內、構造器形參、構造器內部的變量
    • 關于權限修飾符的不同。屬性可以在聲明屬性時,指明其權限,使用權限修飾符。常用的權限修飾符:private、public、缺省、protected。局部變量不可以使用權限修飾符。
    • 默認初始化值的情況
      • 屬性:類的屬性,根據其類型,都有默認初始化值。整型(byte、short、int、long):0;浮點型(float、double):0.0;字符型(char):0(或’\u0000’);布爾型(boolean):false;引用數據類型(類、數組、接口):null
      • 局部變量:沒有默認初始值。意味著,我們在調用局部變量之前,一定要顯式賦值。特別地,形參在調用時,我們賦值即可。
    • 在內存中加載的位置:屬性加載在堆空間中(非static);局部變量加載在??臻g

4、類的成員之二:方法

方法的聲明

權限修飾符 返回值類型 方法名(形參列表){方法體 } // 注意:static、final、abstract來修飾的方法,后面再講

返回值類型:有返回值 VS 沒有返回值

  • 如果方法有返回值,則必須在方法聲明時,指定返回值的類型。同時,方法中,需要使用return關鍵字來返回指定類型的變量或常量:“return 數據”。
  • 如果方法沒有返回值,則方法聲明時,使用void來表示。通常,沒有返回值的方法中,就不需要使用return。但是,如果使用的話,只能“return;”表示結束此方法的意思。

return 關鍵字的使用

  • 使用范圍:使用在方法體中
  • 作用:1、結束方法;2、針對于有返回值類型的方法,使用"return 數據"方法返回所要的數據。
  • 注意點:return關鍵字后面不可以聲明執行語句。

方法的使用

  • 方法的使用中,可以調用當前類的屬性或方法。特殊的,方法A中又調用了方法A:遞歸方法
  • 方法中不可以定義方法。

理解“萬事萬物皆對象”

  • 在Java語言范疇中,我們都將功能、結構等封裝到類中,通過類的實例化,來調用具體的功能接口
    • Scanner, String等
    • 文件:File
    • 網絡資源:URL
  • 涉及到Java與前端Html、后端的數據庫交互時,前后端的結構在Java層面交互時,都體現為類和對象。

方法的重載(overload)

  • 重載的概念:在同一個類中,允許存在一個以上的同名方法,只要它們的參數個數或者參數類型不同即可。
  • 重載的特點:與返回值類型無關,只看參數列表,且參數列表必須不同(參數個數或參數類型)。調用時,根據方法參數列表的不同來區分。
// 返回兩個整數的和 int add(int x, int y) {return x+y;} // 返回三個整數的和 int add(int x, int y, int z) {return x+y+z;} // 返回兩個小數的和 double add(double x, double y) {return x+y;}

可變個數的形參

JavaSE 5.0中提供了Varargs(variable number of arguments)機制,允許直接定義能和多個實參相匹配的形參。從而,可以用一種更簡單的方式,來傳遞個數可以變的實參。

// JDK 5.0以前:采用數組形參來定義方法,傳入多個同一類型的變量 public static void test(int a, String[] books); // JDK 5.0:采用可變個數形參來定義方法,傳入多個同一類型變量 public static void test(int a, String...books);
  • 聲明格式:方法名(參數的類型名…參數名)
  • 可變參數:方法參數部分指定類型的參數個數是可變多個:0個,1個或多個
  • 可變個數形參的方法和同名的方法之間,彼此構成重載
  • 可變參數方法的使用與方法參數部分使用數組是一致的
  • 方法的參數部分有可變形參,需要放在形參聲明的最后
  • 在一個方法的形參位置,最多只能聲明一個可變個數形參
public static void main(String[] args) {DemoTest test = new DemoTest();test.show(12); // show(int i)test.show("hello"); // show(String s)test.show("hello","hello"); // show(String ... s)test.show(); // show(String ... s)test.show(new String[] {"AA", "BB", "CC"}); // show(String ... s) }public void show(int i) {System.out.println("show(int i)"); }public void show(String s) {System.out.println("show(String s)"); }public void show(String ... s) {System.out.println("show(String ... s)"); }

方法參數的值傳遞機制

Java的實參值如何傳入方法呢?

  • Java里方法的參數傳遞方式只有一種:值傳遞。即將實際參數值的副本(復制品)傳入方法內,而參數本身不受影響。
    • 形參是基本數據類型:將實參基本數據類型變量的“數據值”傳遞給形參
    • 形參是引用數據類型:將實參引用數據類型變量的“地址值”傳遞給形參
int[] arr = new int[] {1,2,3}; System.out.println(arr); //地址值 char[] arr1 = new char[] {'a', 'b', 'c'}; // println()方法被重載,所以輸出的不是地址值 System.out.println(arr1); //abc

5、面向對象特征之一:封裝性

四種訪問權限修飾符

  • Java權限修飾符public、protected、private置于類的成員定義前,用來限定對象對該類成員的訪問權限
修飾符類內部同一個包不同包的子類同一個工程
privateYes
(缺省)YesYes
protectedYesYesYes
publicYesYesYesYes

對于class的權限修飾只可以用public和default(缺省)。

  • public類可以在任意地方被訪問。
  • default類只可以被同一個包內部的類訪問。

什么是封裝性?

  • 隱藏對象內部的復雜性,只對外公開簡單的接口。便于外界調用,從而提高系統的可拓展性、可維護性。通俗的說,把該隱藏的隱藏起來,該暴露的暴露出去。這就是封裝性的設計思想。

封裝性的體現

  • Java規定的四種權限(從小到大排列):private、缺省、protected、public
  • 4種權限可以修飾類及類的內部結構:屬性、方法、構造器、內部類
  • 具體的,4中權限都可以用來修飾類的內部結構:屬性、方法、構造器、內部類;修飾類的話,只能使用:缺省、public

總結:Java提供了4種權限修飾符來修飾類及類的內部結構,體現類及類的內部結構在被調用時的可見性的大小

6、類的成員之三:構造器

構造器的作用

  • 創建對象
  • 初始化對象的信息

說明

  • 如果沒有顯示的定義類的構造器的話,則系統默認提供一個空參的構造器,默認構造器的權限修飾符與類修飾符一致
  • 定義構造器的格式:權限修飾符 類名(形參列表){}
  • 一個類中定義的多個構造器,彼此構成重載
  • 一旦我們顯式的定義了類的構造器之后,系統就不再提供默認的空參構造器
  • 一個類中,至少會有一個構造器

屬性賦值的過程

  • 默認初始化
  • 顯式初始化
  • 構造器中的初始化
  • 通過“對象.屬性”或“對象.方法”的方式賦值

7、拓展知識

JavaBean

  • JavaBean是一種Java語言寫成的可重用組件。
  • 所謂JavaBean,是指符合如下標準的Java類:
    • 類是公共的
    • 有一個無參的公共的構造器
    • 有屬性,且有對應的get、set方法

UML類圖

  • +表示public類型,-表示private類型,#表示protected類型
  • 方法的寫法:方法的類型(+、-) 方法名(參數名: 參數類型): 返回值類型
  • 屬性::前是屬性名,:后是屬性的類型

8、關鍵字:this

  • this可以用來修飾、調用:屬性、方法、構造器
  • this修飾屬性和方法時可以理解為:當前對象或當前正在創建的對象
    • 在類的方法中,我們可以使用“this.屬性”或者“this.方法”的方式,調用當前對象屬性或方法。但是通常情況下,我們都選擇省略"this."。特殊情況下,如果方法的形參和類的屬性同名時,我們必須顯示的使用“this.變量”的方式,表明此變量是屬性,而非形參。
    • 在類的構造器中,我們可以使用“this.屬性”或“this.方法”的方式,調用當前正在創建的對象屬性或方法,但是通常情況下,我們都選擇省略"this."。特殊情況下,如果構造器的形參和類的屬性同名時,我們必須顯式的使用“this.變量”的方式,表明此變量是屬性,而非形參。
  • this調用構造器
    • 我們在類的構造器中,可以顯式的使用“this(形參列表)”方式,調用本類中指定的其他構造器
    • 構造器中不能通過“this(形參列表)”方式調用自己
    • 如果一個類中有n個構造器,則最多有n-1個構造器中使用了“this(形參列表)”
    • 規定,“this(形參列表)”必須聲明在當前構造器的首行,因此構造器內部,最多只能聲明一個“this(形參列表)”,用來調用其他的構造器

9、關鍵字:package

  • 為了更好的實現項目中類的管理,提供了包的概念
  • 使用package聲明類或接口所屬的包,聲明在源文件的首行
  • 包,屬于標識符,遵循標識符的命名規則、規范(xxxyyyzzz)、“見名知意”
  • 每“.”一次,就表示一層文件目錄

補充:同一個包下,不能命名同名的接口、類;不同包下,可以命名同名的接口、類。

10、關鍵字:import

  • 在源文件中使用import顯示的導入指定包下的類或接口
  • 聲明在包的聲明和類的聲明之間
  • 如果需要導入多個類或者接口,那么就并列顯式多個import語句即可
  • 舉例:可以使用java.util.*的方式,一次性導入util包下的所有的類或接口
  • 如果導入的類或接口是java.lang包下的,或者是當前包下的,則可以省略此import語句
  • 如果在代碼中使用不同包下的同名的類。那么就需要使用類的全類名的方式指明調用的是哪個類
  • 如果已導入java.a包下的類。那么如果需要使用a包的子包下的類的話,仍然需要導入。
  • import static組合的使用:調用指定類或接口下的靜態的屬性或方法

11、面向對象特征之二:繼承性

繼承性的好處

  • 減少了代碼的冗余,提高了代碼的復用性
  • 便于功能的拓展
  • 為之后多態性的使用,提供了前提

繼承性的說明

  • 繼承性的格式: class A extends B{}
  • 體現:一旦子類A繼承父類B以后,子類A中就獲取了父類B中的聲明的所有的屬性和方法。特別的,父類中聲明為private的屬性或方法,子類繼承父類以后,仍然認為獲取了父類中的私有的結構。只是因為封裝性的影響,使得子類不能直接調用父類的結構而已。
  • 子類繼承父類以后,還可以聲明自己特有的屬性或方法:實現功能的拓展

Java中關于繼承性的規定

  • 一個類可以被多個子類繼承
  • Java中類的單繼承性:一個類只能有一個父類
  • 子父類是相對的概念
  • 子類直接繼承的父類稱為直接父類;間接繼承的父類稱為間接父類
  • 子類繼承父類以后,就獲取了直接父類以及所有間接父類中聲明的屬性和方法

補充說明

  • 如果我們沒有顯示的聲明一個類的父類的話,則此類繼承于java.lang.Object類
  • 所有的java類(除java.lang.Object類之外)都直接或間接的繼承于java.lang.Object類
  • 意味著,所有的java類都具有java.lang.Object類聲明的功能。

方法的重寫(override/overwrite)

  • 重寫:子類繼承父類以后,可以對父類中同名同參數的方法,進行覆蓋操作
  • 應用:重寫以后,當創建子類對象以后,通過子類對象調用子父類中的同名同參數的方法時,實際執行的是子類重寫父類的方法
  • 重寫的規定
    • 子類重寫的方法的方法名和形參列表與父類被重寫的方法的方法名和形參列表相同
    • 子類重寫的方法的權限修飾符不小于父類被重寫的方法的權限修飾符
      • 特殊情況:子類不能重寫父類中聲明為private權限的方法
    • 返回值類型:
      • 父類被重寫的方法的返回值類型是void,則子類重寫的方法的返回值類型只能是void
      • 父類被重寫的方法的返回值類型是A類型,則子類重寫的方法的返回值類型可以是A類或A類的子類
      • 父類被重寫的方法的返回值類型是基本數據類型(比如:double),則子類重寫的方法的返回值類型必須是相同的。
    • 子類重寫的方法拋出的異常類型不大于父類被重寫的方法拋出的異常類型
    • 子類和父類中的同名同參數的方法要么都聲明為非static的(考慮重寫),要么都聲明為static的(不是重寫)。

12、關鍵字:super

  • super可以用來調用:屬性、方法、構造器
  • super的使用
    • 我們可以在子類的方法或構造器中。通過使用"super.屬性"或"super.方法"的方式,顯式的調用父類中聲明的屬性或方法。但是,通常情況下,我們習慣省略"super."
    • 特殊情況:當子類和父類中定義了同名的屬性時,我們要想要在子類中調用父類中聲明的屬性,則必須顯式的使用"super.屬性"的方式,表明調用的是父類中聲明的屬性,否則默認是調用子類的屬性。
    • 特殊情況:當子類重寫了父類中的方法以后,我們想在子類中的方法中調用父類中被重寫的方法時,則必須顯式使用"super.方法"的方式,表明調用的是父類中被重寫的方法,否則默認是調用子類的方法。
  • super調用構造器
    • 我們可以在子類的構造器中顯式的使用"super(形參列表)"的方式,調用父類中聲明的指定的構造器
    • "super(形參列表)"的使用,必須聲明在子類構造器的首行
    • 我們在類的構造器中,針對于"this(形參列表)"或"super(形參列表)"只能二選一,不能同時出現
    • 在構造器的首行,沒有顯示的聲明"this(形參列表)“或"super(形參列表)”,則默認調用的是父類中的空參的構造器
    • 在類的多個構造器中,至少有一個類的構造器中使用了"super(形參列表)",調用父類中的構造器

子類對象實例化的全過程

  • 從結果上來看:(繼承性)
    • 子類繼承父類以后,就獲取了父類中聲明的屬性或方法。
    • 創建子類的對象,在堆空間中,就會加載所有父類中聲明的屬性
  • 從過程上來看:
    • 當我們通過父類的構造器創建子類對象時,我們一定會直接或間接的調用其父類的構造器,進而調用父類的父類的構造器,直到調用了java.lang.Object類中空參的構造器為止。正因為加載過所有的父類的結構,所以才可以看到內存中有父類中的結構,子類對象才可以考慮進行調用。
  • 明確:雖然創建子類對象時,調用了父類的構造器,但是自始至終就創建過一個對象,即為new的子類對象。

13、面向對象特征之三:多態性

  • 理解多態性:可以理解為一個事物的多種形態。
  • 何為多態性:
    • 對象的多態性:父類的引用指向子類的對象(或子類的對象賦給父類的引用)
  • 多態的使用,虛擬方法調用
    • 有了對象的多態性以后,我們在編譯期,只能調用父類中聲明的方法,但在運行期,我們實際執行的是子類重寫父類的方法。
    • 總結:編譯,看左邊;運行,看右邊。
  • 多態性的使用前提:
    • 類的繼承關系
    • 方法的重寫
  • 對象的多態性,只適用于方法,不適用于屬性(編譯和運行都看左邊)

區分方法的重載與重寫

  • 二者定義的不同:
    • 重載:在同一個類中,允許存在一個以上的同名方法,只要它們的參數個數或者參數類型不同即可。
    • 重寫:子類繼承父類以后,可以對父類中同名同參數的方法,進行覆蓋操作
  • 從編譯和運行的角度看:
    • 重載,是指允許存在多個同名方法,而這些方法的參數不同。編譯器根據方法不同的參數表,對同名方法的名稱做修飾。對于編譯器而言,這些同名方法就成了不同的方法。它們的調用地址在編譯期就綁定了。Java的重載是可以包括父類和子類的,即子類可以重載父類的同名不同參數的方法。
    • 所以:對于重載而言,在方法調用之前,編譯期就已經確定了所要調用的方法,這稱為“早綁定”或“靜態綁定”
    • 而對于多態,只有等到方法調用的那一刻,解釋器運行器才會確定所要調用的具體方法,這稱為“晚綁定”或“動態綁定”。

instanceof 操作符

  • instanceof 關鍵字的使用:a instanceof A:判斷對象a是否是類A的實例。如果是,返回true;如果不是,返回false
  • 使用情境: 為了避免在向下轉型時出現ClassCastException的異常,我們在向下轉型之前,先進行instanceof的判斷,一旦返回true,就進行向下轉型。如果返回false,就不進行向下轉型。
  • 如果類B是類A的父類,且a instanceof A返回true,則a instanceof B也返回true

==和equals的區別

  • ==既可以比較基本類型也可以比較引用類型。對于基本類型就是比較值,對于引用類型就是比較內存地址
  • equals的話,它是屬于java.lang.Object類里面的方法,如果該方法沒有被重寫過默認也是==;我們可以看到String等類的equals方法是被重寫過的,而且String類在日常開發中用的比較多,久而久之,形成了equals是比較值的錯誤觀點
  • 具體要看自定義類里有沒有重寫Object的equals方法來判斷
  • 通常情況下,重寫equals方法,會比較類中的相應屬性是否都相等

Java中的JUnit單元測試

  • 創建Java類,進行單元測試。此時的Java類要求:
    • 此類是public的
    • 此類提供公共的無參的構造器
  • 此類中聲明單元測試方法。此時的單元測試方法的權限是public,沒有返回值,沒有形參
  • 此單元測試方法上需要聲明注解:@Test
  • 寫完代碼后,左鍵雙擊單元測試方法名,右鍵:run as - JUnit Test
  • 說明:如果執行結果沒有任何異常:綠條;如果執行結果出現異常:紅條

14、包裝類(Wrapper)的使用

基本數據類型包裝類
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

Byte、Short、Integer、Long、Float、Double的父類為Number;Boolean、Character的父類為Object

基本類型、包裝類與String類間的轉換

  • 基本數據類型 --> 包裝類:自動裝箱
  • 包裝類 --> 基本數據類型:自動拆箱
  • 基本數據類型 --> String類:String類的valueOf()方法
  • String類 --> 基本數據類型:調用相應包裝類的parseXxx(String)靜態方法
  • 包裝類 --> String類:包裝類對象的toString()方法
// 使用parseBoolean時,如果s非空且在忽略大小寫的情況下等于true,則返回true;否則返回false public static boolean parseBoolean(String s) {return "true".equalsIgnoreCase(s); } // 三元運算符運算過程中會盡量使兩邊的類型一致,所以new Integer(1)被自動提升了類型 Object o1 = true ? new Integer(1) : new Double(2.0); System.out.println(o1); // 1.0Object o2; if (true) {o2 = new Integer(1); } else {o2 = new Double(2.0); } System.out.println(o2); // 1
  • Integer內部定義了IntegerCache結構,IntegerCache中定義了Integer[],保存了從-128到127范圍的整數。如果我們使用自動裝箱的方式,給Integer賦值的范圍在-128到127范圍內時,可以直接使用數組中的元素,不用再去new了。目的為了提高效率
Integer i = new Integer(1); Integer j = new Integer(1); System.out.println(i == j);// falseInteger m = 1; Integer n = 1; System.out.println(m == n);// trueInteger x = 128; Integer y = 128; System.out.println(x == y);// false

15、關鍵字:static

  • 使用static修飾屬性:靜態變量(或類變量)
    • 屬性,按是否使用static修飾,又分為:靜態屬性 vs 非靜態屬性(實例變量)
      • 實例變量:我們創建了類的多個對象,每個對象都獨立擁有一套類中的非靜態屬性。當修改其中一個對象的非靜態屬性時,不會導致其他對象中同樣的屬性值修改
      • 靜態變量:我們創建了類的多個對象,多個對象共享同一個靜態變量。當通過某一個對象修改靜態變量時,會導致其他對象調用此靜態變量時,是修改過了的
    • static修飾屬性的其他說明
      • 靜態變量隨著類的加載而加載??梢酝ㄟ^"類.靜態變量"的方式進行調用
      • 靜態變量的加載要早于對象的創建
      • 由于類只會加載一次,則靜態變量在內存中也只會存在一份:存在方法區的靜態域中
  • 使用static修飾方法:靜態方法
    • 隨著類的加載而加載,可以通過"類.靜態方法"的方式進行調用
    • 靜態方法中,只能調用靜態的方法或屬性;非靜態方法中,既可以調用非靜態的方法或屬性,也可以調用靜態的方法或屬性
  • static注意點
    • 在靜態的方法內,不能使用this關鍵字、super關鍵字
  • 開發中,如何確定一個屬性是否要聲明為static的?
    • 屬性可以被多個對象所共享的,不會隨著對象的不同而不同
    • 類中的常量也常常聲明為static
  • 開發中,如何確定一個方法是否要聲明為static的?
    • 操作靜態屬性的方法,通常設置為static的
    • 工具類中的方法,習慣上聲明為static的
/*** 單例設計模式:* 1、所謂的類的單例設計模式,就是采取一定的方法保證在整個的軟件系統中,對某個類只能存在一個對象實例。* 2、如何實現?* 餓漢式 vs 懶漢式* 3、區分餓漢式和懶漢式* 餓漢式:* 壞處:對象加載時間過長。* 好處:餓漢式是線程安全的* 懶漢式:* 好處:延遲對象的創建。* 目前的寫法壞處:線程不安全。(到多線程內容時,再修改)*/// 餓漢式 class Bank {// 1、私有化類的構造器private Bank() {}// 2、內部創建類的對象// 4、要求此對象也必須聲明為靜態的private static Bank instance = new Bank();// 3、提供公共的靜態的方法,返回類的對象public static Bank getInstance() {return instance;} }// 懶漢式 class Order {// 1、私有化類的構造器private Order() {}// 2、聲明當前類對象,沒有初始化// 4、此對象也必須聲明為static的private static Order instance = null;// 3、聲明public、static的返回當前類對象的方法public static Order getInstance() {if (instance == null) {instance = new Order();}return instance;} }

16、類的成員之四:代碼塊(或初始化塊)

  • 代碼塊的作用:用來初始化類、對象
  • 代碼塊如果有修飾的話,只能使用static
  • 分類:靜態代碼塊 VS 非靜態代碼塊
  • 靜態代碼塊
    • 內部可以有輸出語句
    • 隨著類的加載而執行,而且只執行一次
    • 作用:初始化類的信息
    • 如果一個類中定義了多個靜態代碼塊,則按照聲明的先后順序執行
    • 靜態代碼塊的執行要優先于非靜態代碼塊的執行
    • 靜態代碼塊內只能調用靜態的屬性、靜態的方法,不能調用非靜態的結構
  • 非靜態代碼塊
    • 內部可以有輸出語句
    • 隨著對象的創建而執行
    • 每創建一個對象,就執行一次非靜態代碼塊
    • 作用:可以在創建對象時,對對象的屬性等進行初始化
    • 如果一個類中定義了多個非靜態代碼塊,則按照聲明的先后順序執行
    • 非靜態代碼塊內可以調用靜態的屬性、靜態的方法,或非靜態的屬性、非靜態的方法

總結:由夫及子,靜態先行

屬性賦值的過程

  • 默認初始化
  • 顯式初始化/在代碼塊中賦值
  • 構造器中初始化
  • 有了對象以后,可以通過"對象.屬性"或"對象.方法"的方式,進行賦值

顯式初始化和在代碼塊中賦值的順序先后取決于代碼先后順序

17、關鍵字:final

  • final可以用來修飾的結構:類、方法、變量
  • final用來修飾一個類:此類不能被其他類所繼承。
  • final用來修飾方法:表明此方法不可以被重寫
  • final用來修飾變量:此時的"變量"就稱為是一個常量
    • final修飾屬性:可以考慮賦值的位置有:顯示初始化、代碼塊中初始化、構造器中初始化
    • final修飾局部變量:尤其是使用final修飾形參時,表明此形參是一個常量。當我們調用此方法時,給常量形參賦一個實參。一旦賦值以后,就只能在方法體內使用此形參,但不能進行重新賦值。

static final 用來修飾屬性:全局變量

18、關鍵字:abstract

  • abstract可以用來修飾的結構:類、方法
  • abstract修飾類:抽象類
    • 此類不能實例化
    • 抽象類中一定要有構造器,便于子類實例化時調用(涉及:子類對象實例化的全過程)
    • 開發中,都會提供抽象類的子類,讓子類對象實例化,完成相關的操作
  • abstract修飾方法:抽象方法
    • 抽象方法只要方法的聲明,沒有方法體
    • 包含抽象方法的類,一定是一個抽象類。反之,抽象類中可以沒有抽象方法的。
    • 若子類重寫了父類中的所有抽象方法后,此子類才可以實例化;若子類沒有重寫父類中的所有的抽象方法,則此子類也是一個抽象類,需要使用abstract修飾

注意點:abstract不能用來修飾:屬性、構造器等結構;abstract不能用來修飾私有方法、靜態方法、final的方法、final的類

匿名對象

method(new Student()); //匿名對象Worker worker = new Worker(); method1(worker); //非匿名的類非匿名的對象method1(new Worker()); //非匿名的類匿名的對象// 創建匿名子類的非匿名對象 Person p = new Person() {@Overridepublic void eat() {System.out.println("吃東西");} }// 創建匿名子類的匿名對象 method1(new Person() {@Overridepublic void eat() {System.out.println("吃東西");} });

19、關鍵字:interface

  • Java中,接口和類是并列的兩個結構
  • 如何定義接口,定義接口中的成員
    • JDK7及以前:只能定義全局變量和抽象方法
      • 全局常量:public static final的,但是書寫時,可以省略不寫
      • 抽象方法:public abstract的
    • JDK8:除了定義全局常量和抽象方法之外,還可以定義靜態方法、默認方法
  • 接口中不能定義構造器!意味著接口不可以實例化
  • Java開發中,接口通過讓類去實現(implements)的方式來使用。如果實現類覆蓋了接口中的所有抽象方法,則此實現類就可以實例化;如果實現類沒有覆蓋接口中所有的抽象方法,則此實現類仍為一個抽象類。
  • Java類可以實現多個接口:彌補了Java單繼承性的局限性。格式:class AA extends BB implements CC,DD,EE
  • 接口與接口之間可以繼承,而且可以多繼承。格式:interface AA extends BB,CC
  • 接口的具體使用,體現了多態性
  • 接口,實際上可以看做是一種規范
interface Flyable {// 全局變量public static final int MAX_SPEED = 7900;int MIN_SPEED = 1; // 省略了public static final// 抽象方法public abstract void fly();// 省略了public abstractvoid stop();// Interfaces cannot have constructors// public Flyable() {} } interface A {int x = 0; }class B {int x = 1; }class C extends B implements A {public void pX() {// 編譯不通過,因為x是不明確的// System.out.println(x);System.out.println(super.x); // 1System.out.println(A.x); // 0} }

JDK8:除了定義全局常量和抽象方法之外,還可以定義靜態方法、默認方法

public interface CompareA {// 靜態方法public static void method1() {System.out.println("CompareA:北京");}// 默認方法public default void method2() {System.out.println("CompareA:上海");}default void method3() {System.out.println("CompareA:上海");} }class SubClass extends SuperClass implements CompareA, CompareB {public void method2() {System.out.println("SubClass:上海");}public void method3() {System.out.println("SubClass:深圳");}// 知識點5:如何在子類(或實現類)的方法中調用父類、接口中被重寫的方法public void myMethod() {method3();//調用了自己定義的重寫的方法super.method3(); //調用的是父類中聲明的//調用接口中的默認方法CompareA.super.method3();CompareB.super.method3();} }public class SubClassTest {public static void main(String[] args) {SubClass s = new SubClass();// 知識點1:接口中定義的靜態方法,只能通過接口來調用// s.method1(); // 編譯錯誤// SubClass.method1(); // 編譯錯誤CompareA.method1();// 知識點2:通過實現類的對象,可以調用接口中的默認方法。// 如果實現類重寫了接口中的默認方法,調用時,仍然調用的是重寫以后的方法。s.method2();// 知識點3:如果子類(或實現類)繼承的父類和實現的接口中聲明了同名同參數的默認方法,// 那么子類在沒有重寫此方法的情況下,默認調用的是父類中的同名同參數的方法(類優先原則)。// 知識點4:如果實現類實現了多個接口,而這多個接口中定義了同名同參數的默認方法,//那么在實現類沒有重寫此方法的情況下,會報錯——接口沖突//這就需要我們必須在實現類中重寫此方法s.method3();} }

20、類的內部成員之五:內部類

  • Java中允許將一個類A聲明在另一個類B中,則類A就是內部類,類B稱為外部類

  • 內部類的分類:成員內部類(靜態、非靜態) VS 局部內部類(方法內、代碼塊內、構造器內)

  • 成員內部類:

    • 作為外部類的成員:
      • 調用外部類的結構
      • 可以被static修飾
      • 可以被4種不同的權限修飾
    • 作為一個類:
      • 類內可以定義屬性、方法、構造器等
      • 可以被final修飾,表示此類不能被繼承。言外之意,不使用final就可以被繼承
      • 可以被abstract修飾
  • 如何實例化成員內部類的對象

// 創建Dog實例(靜態的成員內部類): Person.Dog dog = new Person.Dog(); dog.show(); // 創建Bird實例(非靜態的成員內部類): // Person.Bird bird = new Person.Bird(); // 編譯錯誤 Person p = new Person(); Person.Bird bird = p.new Bird(); bird.sing();
  • 如何在成員內部類中區分調用外部類的結構
public void sing() {// 調用外部類的非靜態方法Person.this.eat();eat();// 調用外部類的非靜態屬性System.out.println(age); }public void display(String name) {System.out.println(name); // 方法的形參System.out.println(this.name); // 內部類的屬性System.out.println(Person.this.name); // 外部類的屬性 }
  • 開發中局部內部類的使用
public Comparable getComparable() {return new Comparable() {@Overridepublic int compareTo(Object o) {return 0;}} }
  • 在局部內部類的方法中(比如:show),如果要調用外部類所聲明的方法(比如:method)中的局部變量(比如:num)的話,要求此局部變量聲明為final的。
    • JDK 7及之前版本:要求此局部變量顯式的聲明為final的
    • JDK 8及之后版本:可以省略final的聲明
public void method() {//局部變量-JDK 8及之后,final可以省略final int num = 10;class AA {public void show () {// num = 20;System.out.print(num);}} }
  • 成員內部類和局部內部類,在編譯之后,都會生成字節碼文件。格式:
    • 成員內部類:外部類$內部類名.class
    • 局部內部類:外部類$數字 內部類名.class

三、異常處理

1、異常體系結構

  • java.lang.Throwable
    • java.lang.Error:一般不編寫針對性的代碼進行處理
    • java.lang.Exception:可以進行異常的處理
      • 編譯時異常(checked)
        • IOException
          • FileNotFoundException
        • ClassNotFoundException
      • 運行時異常(unchecked)
        • NullPointerException
        • ArrayIndexOutOfBoundsException
        • ClassCastException
        • NumberFormatException
        • InputMismatchException
        • ArithmeticException

2、異常處理的方式一:try-catch-finally

try {//可能出現異常的代碼 } catch (異常類型1 變量名1) {//處理異常的方式1 } catch (異常類型2 變量名2) {//處理異常的方式2 } catch (異常類型3 變量名3) {//處理異常的方式3 } ...... finally {//一定會執行的代碼 }

try-catch-finally的說明

  • 使用try將可能出現異常代碼包裝起來。在執行過程之,一旦出現異常,就會生成一個對應異常類的對象,根據此對象的類型,去catch中進行匹配
  • 一旦try中的異常對象匹配到某一個catch時,就進入catch中進行異常的處理。一旦處理完成,就跳出當前的try-catch結構(在沒有寫finally的情況)。繼續執行其后的代碼
  • catch中的異常類型如果沒有子父類關系,則誰聲明在上,誰聲明在下無所謂;如果滿足子父類關系,則要求子類一定聲明在父類的上面,否則報錯。
  • 常用的異常對象處理的方式:
    • String getMessage()
    • printStackTrace()
  • 在try結構中聲明的變量,在出了try結構以后,就不能再被調用
  • try-catch-finally結構可以嵌套

try-catch-finally的體會

  • 使用try-catch-finally處理編譯時異常,使得程序在編譯時就不再報錯,但是運行時仍可能報錯。相當于我們使用try-catch-finally將一個編譯時可能出現的異常,延遲到運行時出現。
  • 開發中,由于運行時異常比較常見,所以我們通常就不針對運行時異常編寫try-catch-finally了。針對編譯時異常,我們一定要考慮異常的處理。

finally的說明

  • finally是可選的
  • finally中聲明的是一定會被執行的代碼。即使catch中又出現異常了,try中有return語句,catch中有return語句等情況。
  • 像數據庫連接、輸入輸出流、網絡編程Socket等資源,JVM是不能自動的回收的,我們需要自己手動的進行資源的釋放。此時的資源釋放,就需要聲明在finally中。

3、異常處理的方式二:throws + 異常類型

  • "throws + 異常類型"寫在方法的聲明處。指明此方法執行時,可能會拋出的異常類型。一旦當方法體執行時,出現異常,仍會在異常代碼處生成一個異常類的對象,此對象滿足throws后異常類型時,就會被拋出。異常代碼后續的代碼,就不再執行!
  • try-catch-finally:真正的將異常給處理掉了;throws的方式只是將異常拋給了方法的調用者,并沒有真正將異常處理掉。
  • 開發中如何選擇使用try-catch-finally還是使用throws?
    • 如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味著如果子類重寫的方法中有異常,必須使用try-catch-finally方式處理
    • 執行的方法a中,先后又調用了另外的幾個方法,這幾個方法是遞進關系執行的。我們建議這幾個方法使用throws的方式進行處理。而執行的方法a可以考慮是用try-catch-finally方式進行處理。

4、自定義異常類

  • 繼承于現有的異常結構:RuntimeException、Exception
  • 提供全局常量:serialVersionUID
  • 提供重載的構造器

5、附加:Eclipse中的快捷鍵

  • 補全代碼的聲明:alt + /
  • 快速修飾:ctrl + l
  • 批量導包:ctrl + shift + o
  • 使用單行注釋:ctrl + /
  • 使用多行注釋:ctrl + shift + /
  • 取消多行注釋:ctrl + shift + \
  • 復制指定行的代碼:ctrl + alt + down 或 ctrl + alt + up
  • 刪除指定行的代碼:ctrl + d
  • 上下移動代碼:alt + up 或 alt + down
  • 切換到下一行代碼空位:shift + enter
  • 切換到上一行代碼空位:ctrl + shift + enter
  • 如何查看源碼:ctrl + 選中指定的結構 或 ctrl + shift + t
  • 退回到前一個編輯的頁面:alt + left
  • 進入到下一個編輯的頁面(針對與上面那條來說的):alt + right
  • 光標選中指定的類,查看繼承樹結構:ctrl + t
  • 復制代碼:ctrl + c
  • 撤銷:ctrl + z
  • 反撤銷:ctrl + y
  • 剪切:ctrl + x
  • 粘貼:ctrl + v
  • 保存:ctrl + s
  • 全選:ctrl + a
  • 格式化代碼:ctrl + shift + f
  • 選中數行,整體往后移動:tab
  • 選中數行,整體往前移動:shift + tab
  • 在當前類中,顯示類結構,并支持搜索指定的方法、屬性等:ctrl + o
  • 批量修改指定的變量名、方法名、類名等:alt + shift + r
  • 選中的結構的大小寫的切換:變成大寫:ctrl + shift + x
  • 選中的結構的大小寫的切換:變成小寫:ctrl + shift + y
  • 調出生成getter/setter/構造器等結構:alt + shift + s
  • 顯示當前選擇資源(工程 or 文件)的屬性:alt + enter
  • 快速查找:參照選中的Word快速定位到下一個:ctrl + k
  • 關閉當前窗口:ctrl + w
  • 關閉所有的窗口:ctrl + shift + w
  • 查看指定的機構使用過的地方:ctrl + alt + g
  • 查找與替換:ctrl + f
  • 最大化當前的View:ctrl + m
  • 直接定位到當前行的首位:home
  • 直接定位到當前行的末位:end

Java高級編程

一、多線程

1、基本概念:程序、進程、線程

1.1、程序

  • 概念:是為完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼。

1.2、進程

  • 概念:程序的一次執行過程,或是正在運行的一個程序。
  • 說明:進程作為資源分配的單位,系統在運行時會為每個進程分配不同的內存區域。

1.3、線程

  • 概念:進程可進一步細化為線程,是一個程序內部的一條執行路徑。
  • 說明:線程作為調度和執行的單位,每個線程擁有獨立的運行棧和程序計數器(pc),線程切換的開銷小。
  • 每個線程,擁有自己獨立的:虛擬機棧、程序計數器
  • 多個線程,共享同一個進程中的結構:方法區、堆

1.4、單核CPU和多核CPU的理解

  • 單核CPU,其實是一種假的多線程,因為在一個時間單元內,也只能執行一個線程的任務。但是因為CPU時間單元特別短,因此感覺不出來。
  • 如果是多核的話,才能更好的發揮多線程的效率。
  • 一個Java應用程序java.exe,其實至少有三個線程:main()主線程,gc()垃圾回收線程,異常處理線程。當然如果發生異常,會影響主線程。

1.5、并行與并發

  • 并行:多個CPU同時執行多個任務。
  • 并發:一個CPU(采用時間片)同時執行多個任務。

1.6、使用多線程的優點

  • 背景:以單個CPU為例,只使用單個線程先后完成多個任務(調用多個方法),肯定比用多個線程來完成用的時間更短,為何仍需多線程呢?
  • 多線程程序的優點:
    • 1、提高應用程序的響應。對圖形化界面更有意義,可增強用戶體驗。
    • 2、提高計算機系統CPU的利用率
    • 3、改善程序結構。將既長又復雜的進程分為多個線程,獨立運行,利于理解和修改

1.7、何時需要多線程

  • 程序需要同時執行兩個或多個任務
  • 程序需要實現一些需要等待的任務時,如用戶輸入、文件讀寫操作、網絡操作、搜索等。
  • 需要一些后臺運行的程序時。

2、線程的創建和使用

2.1、創建多線程的方式一:繼承Thread類

  • 1、創建一個繼承于Thread類的子類
  • 2、重寫Thread類的run() --> 將此線程執行的操作聲明在run()中
  • 3、創建Thread類的子類的對象
  • 4、通過此對象調用start(),start()的作用:
    • 1、啟動當前線程
    • 2、調用當前線程的run()
//1、創建一個繼承于Thread類的子類 class MyThread extends Thread {//2、重寫Thread類的run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(i);}}} }public class ThreadTest {public static void main(String[] args) {//3、創建Thread類的子類的對象MyThread t1 = new MyThread();//4、通過此對象調用start()t1.start();// 或者通過創建Thread類的匿名子類的方式new Thread() {@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName() + ":" + i);}}}}.start();} }
  • 注意點1:我們不能通過直接調用run()的方式啟動線程
  • 注意點2:再啟動一個線程需要重新創建一個線程的對象,不可以讓已經start()的線程再start(),否則會報IllegalThreadStateException異常

2.2、Thread類的有關方法

  • void start():啟動當前線程,調用當前線程的run()
  • run():通常需要重寫Thread類中的此方法,將創建的線程要執行的操作聲明在此方法中
  • String getName():獲取當前線程的名字
  • void setName(String name):設置當前線程的名字
  • static Thread currentThread():靜態方法,獲取執行當前代碼的線程
  • static void yield():釋放當前CPU的執行權
  • join():在線程a中調用線程b的join(),此時線程a就進入阻塞狀態,直到線程b完全執行完以后,線程a才結束阻塞狀態
  • static void sleep(long millitime):讓當前線程“睡眠”指定的millitime毫秒。在指定的millitime毫秒時間內,當前線程是阻塞狀態。
  • stop():已過時。當執行此方法時,強制結束當前線程。
  • boolean isAlive():判斷當前線程是否存活

2.3、線程的調度

  • 調度策略
    • 時間片
    • 搶占式:高優先級的線程搶占CPU
  • Java的調度方法
    • 同優先級線程組成先進先出隊列,使用時間片策略
    • 對高優先級,使用優先調度的搶占式策略

2.4、線程的優先級

  • 線程的優先等級
    • MAX_PRIORITY:10
    • MIN_PRIORITY:1
    • NORM_PRIORITY:5 --> 默認優先級
  • 涉及的方法
    • getPriority():獲取線程的優先級
    • setPriority(int newPriority):設置線程的優先級
  • 線程創建時繼承父線程的優先級
  • 低優先級只是獲得調度的概率低,并非一定是在高優先級線程之后才被調度

2.5、創建多線程的方式二:實現Runnable接口

  • 1、創建一個實現了Runnable接口的類
  • 2、實現類去實現Runnable中的抽象方法:run()
  • 3、創建實現類的對象
  • 4、將此對象作為參數傳遞到Thread類的構造器中,創建Thread類的對象
  • 5、通過Thread類的對象調用start()
//1、創建一個實現了Runnable接口的類 class MThread implements Runnable {//2、實現類去實現Runnable中的抽象方法:run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(i);}}} }public class ThreadTest1 {public static void main(String[] args) {//3、創建實現類的對象MThread mThread = new MThread();//4、將此對象作為參數傳遞到Thread類的構造器中,創建Thread類的對象Thread t1 = new Thread(mThread);//5、通過Thread類的對象調用start():啟動線程,調用當前線程的run() --> 調用了Runnable類型的target的run()t1.start();//再啟動一個線程Thread t2 = new Thread(mThread);t2.start();} }

2.6、比較創建線程的兩種方式

  • 開發中:優先選擇實現Runnable接口的方式
    • 1、實現的方式沒有類的單繼承性的局限性
    • 2、實現的方式更適合來處理多個線程有共享數據的情況
  • 聯系:public class Thread implements Runnable
  • 相同點:兩種方式都需要重寫run(),將線程要執行的邏輯聲明在run()中

3、線程的生命周期

graph LR A(新建) --> |"調用start()"| B(就緒) B --> |"獲取CPU執行權"| C(運行) C --> |"執行完run();調用線程的stop();出現Error/Exception且沒有處理"| D(死亡) C --> |"失去CPU執行權或yield()"| B C --> |"sleep(long time);join();等待同步鎖;wait();suspend()"| E(阻塞) E --> |"sleep()時間到;join()結束;獲取同步鎖;notify()/notifyAll();resume()"| B

4、線程的同步

4.1、線程同步方式一:同步代碼塊

synchronized(同步監視器) {// 需要被同步的代碼 }
  • 1、操作共享數據的代碼,即為需要被同步的代碼
  • 2、共享數據:多個線程共同操作的變量。
  • 3、同步監視器,俗稱:鎖。任何一個類的對象,都可以充當鎖。
    • 要求:多個線程必須要共用同一把鎖。
  • 補充:在實現Runnable接口創建多線程的方式中,我們可以考慮使用this充當同步監視器
  • 在繼承Thread類創建多線程的方式中,慎用this充當同步監視器,考慮使用當前類充當同步監視器
public class Window1 implements Runnable{private int ticket = 100;Object obj = new Object();@Overridepublic void run() {while (true) {//正確,只要保證多個線程使用同一個對象當做鎖即可// synchronized (obj) {// 此時的this:唯一的Window1的對象synchronized (this) {if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + ticket);ticket--;} else {break;}}}} } public class Window2 extends Thread{private static int ticket = 100;private static Object obj = new Object();@Overridepublic void run() {while (true) {//正確// synchronized (obj) {// 錯誤,因為通過繼承Thread方式,需要通過不同的對象來創建線程// 此時的this代表著不同的對象 // synchronized (this) {// 正確,Class clazz = Window2.class,Window2.class只會加載一次synchronized (Window2.class) {if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + ticket);ticket--;} else {break;}}}} }
  • 好處:同步的方式,解決了線程的安全問題。
  • 局限性:操作同步代碼時,只能有一個線程參與,其他線程等待。相當于一個單線程的過程,效率低。

4.2、線程同步方式二:同步方法

  • 同步方法仍然涉及到同步監視器,只是不需要我們顯式的聲明。
  • 非靜態的同步方法,同步監視器是:this;靜態的同步方法,同步監視器是:當前類本身
public class Window3 implements Runnable{private int ticket = 100;@Overridepublic void run() {while (true) {show();}}private synchronized void show () {//同步監視器:thisif (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + ticket);ticket--;}} } public class Window4 extends Thread {private static int ticket = 100;@Overridepublic void run() {while (true) {show();}}private static synchronized void show () {//同步監視器:Window4.classif (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + ticket);ticket--;}} }

4.3、設計模式:單例模式

// 餓漢式 class Bank {// 1、私有化類的構造器private Bank() {}// 2、內部創建類的對象// 4、要求此對象也必須聲明為靜態的private static Bank instance = new Bank();// 3、提供公共的靜態的方法,返回類的對象public static Bank getInstance() {return instance;} }// 懶漢式方式一:同步方法 class Order {// 1、私有化類的構造器private Order() {}// 2、聲明當前類對象,沒有初始化// 4、此對象也必須聲明為static的private static Order instance = null;// 3、聲明public、static的返回當前類對象的方法public static synchronized Order getInstance() {if (instance == null) {instance = new Order();}return instance;} }// 懶漢式方式二:同步代碼塊 class Order {// 1、私有化類的構造器private Order() {}// 2、聲明當前類對象,沒有初始化// 4、此對象也必須聲明為static的private static Order instance = null;// 3、聲明public、static的返回當前類對象的方法public static Order getInstance() {// 方式一:效率稍差// synchronized (Order.class) {// if (instance == null) {// instance = new Order();// }// return instance;// }// 方式二:效率更高if (instance == null) {synchronized (Order.class) {if (instance == null) {instance = new Order();}}}return instance;} }

4.4、線程的死鎖問題

  • 死鎖
    • 不同的線程分別占用對方需要的同步資源不放棄,都在等待對方放棄自己需要的同步資源,就形成了線程的死鎖
    • 出現死鎖后,不會出現異常,不會出現提示,只是所有的線程都處于阻塞狀態,無法繼續
  • 解決方法
    • 專門的算法、原則
    • 盡量減少同步資源的定義
    • 盡量避免嵌套同步

4.5、線程同步方式三:Lock(鎖)

class Window implements Runnable {private int ticket = 100;// 1、實例化ReentrantLockprivate ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {try {// 2、調用鎖定方法lock()lock.lock();if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + ticket);ticket--;} else {break;}} finally {// 3、調用解鎖方法:unlock()lock.unlock();}}} }
  • 面試題:synchronized與lock的異同?
    • 相同:二者都可以解決線程安全問題
    • 不同:synchronized機制在執行完相應的同步代碼以后,自動的釋放同步監視器;Lock需要手動的啟動同步(Lock()),同時結束同步也需要手動的實現(unlock())
  • 優先使用順序:
    • Lock --> 同步代碼塊 --> 同步方法

5、線程的通信

  • 涉及到的三個方法:

    • wait():一旦執行此方法,當前線程就進入阻塞狀態,并釋放同步監視器
    • notify():一旦執行此方法,就會喚醒被wait()的一個線程。如果有多個線程被wait,就喚醒優先級高的線程。
    • notifyAll():一旦執行此方法,就會喚醒所有被wait的線程
  • 說明:

    • wait(),notify(),notifyAll()三個方法必須使用在同步代碼塊或同步方法中
    • wait(),notify(),notifyAll()三個方法的調用者必須是同步代碼塊或同步方法中的同步監視器,否則會出現IllegalMonitorStateException異常
    • wait(),notify(),notifyAll()三個方法是定義在java.lang.Object類中
  • 面試題:sleep() 和 wait() 的異同?

    • 相同點:一旦執行方法,都可以使得當前的線程進入阻塞狀態
    • 不同點:
      • 1、兩個方法聲明的位置不同:Thread類中聲明sleep(),Object類中聲明wait()
      • 2、調用的要求不同:sleep()可以在任何需要的場景下調用。wait()必須使用在同步代碼塊中
      • 3、關于是否釋放同步監視器:如果兩個方法都使用在同步代碼塊或同步方法中,sleep()不會釋放鎖,wait()會釋放鎖

6、JDK5.0新增線程創建方式

6.1、新增方式一:實現Callable接口

  • 與使用Runnable相比,Callable功能更強大些
    • 相比run()方法,可以有返回值
    • 方法可以拋出異常
    • 支持泛型的返回值
    • 需要借助FutureTask類,比如獲取返回結果
  • Future接口
    • 可以對具體Runnable、Callable任務的執行結果進行取消、查詢是否完成、獲取結果等。
    • FutrueTask是Futrue接口的唯一實現類
    • FutrueTask同時實現了Runnable,Future接口。它既可以作為Runnable被線程執行,又可以作為Future得到Callable的返回值
// 1、創建一個實現Callable的實現類 class NumThread implements Callable {// 2、實現call方法,將此線程需要執行的操作聲明在call()中@Overridepublic Object call() throws Exception {int sum = 0;for (int i = 1; i <= 100; i++) {if (i % 2 == 0) {System.out.println(i);sum += i;}}return sum;} }public class ThreadNew {public static void main(String[] args) {// 3、創建Callable接口實現類的對象NumThread numThread = new NumThread();// 4、將此Callable接口實現類的對象作為傳遞到FutureTask構造器中,創建FutureTask的對象FutureTask futureTask = new FutureTask(numThread);// 5、將FutureTask的對象作為參數傳遞到Thread類的構造器中,創建Thread對象,并調用start()new Thread(futureTask).start();try {// 6、獲取Callable中call方法的返回值// get()返回值即為FutureTask構造器參數Callable實現類重寫的call()的返回值Object sum = futureTask.get();System.out.println("總和為:" + sum);} catch (ExecutionException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}} }

6.2、新增方式二:使用線程池

  • 背景:經常創建和銷毀、使用量特別大的資源,比如并發情況下的線程,對性能影響很大
  • 思路:提前創建好多個線程,放入線程池中,使用時直接獲取,使用完放回池中。可以避免頻繁創建銷毀、實現重復利用。
  • 好處:
    • 提高響應速度(減少了創建新線程的時間)
    • 降低資源消耗(重復利用線程池中線程,不需要每次都創建)
    • 便于線程管理
      • corePoolSize:核心池的大小
      • maximumPoolSize:最大線程數
      • keepAliveTime:線程沒有任務時最多保持多長時間后會終止
  • ExecutorService:真正的線程池接口。常見子類ThreadPoolExecutor
    • void execute(Runnable command):執行任務/命令,沒有返回值,一般用來執行Runnable
    • Future submit(Callable task):執行任務,有返回值,一般用來執行Callable
    • void shutdown():關閉連接池
  • Executors:工具類、線程池的工廠類,用于創建并返回不同類型的線程池
    • Executors.newCachedThreadPool():創建一個可根據需要創建新線程的線程池
    • Executors.newFixedThreadPool(n):創建一個可重用固定線程數的線程池
    • Executors.newSingleThreadPool():創建一個只有一個線程的線程池
    • Executors.newScheduledThreadPool(n):創建一個線程池,它可安排在給定延遲后運行命令或者定期地執行
public class ThreadPool {public static void main(String[] args) {// 1、提供指定線程數量的線程池ExecutorService service = Executors.newFixedThreadPool(10);// 2、執行指定的線程的操作。需要提供實現Runnable接口或Callable接口實現類的對象service.execute(new NumberThread()); // 適用于實現Runnable接口的線程service.submit(new NumberThread1()); // 適用于實現Callable接口的線// 3、關閉連接池service.shutdown();} }

7、附加:關于鎖的操作

7.1、釋放鎖的操作

  • 當前線程的同步方法、同步代碼塊執行結束
  • 當前線程在同步代碼塊、同步方法中遇到break、return終止了該代碼塊、該方法的繼續執行。
  • 當前線程在同步代碼塊、同步方法中出現了未處理的Error或Exception,導致異常結束
  • 當前線程在同步代碼塊、同步方法中執行了線程對象的wait()方法,當前線程暫停,并釋放鎖

7.2、不會釋放鎖的操作

  • 線程執行同步代碼塊或同步方法時,程序調用Thread.sleep()、Thread.yield()方法暫停當前線程的執行
  • 線程執行同步代碼塊時,其他線程調用了該線程的suspend()方法將該線程掛起,該線程不會釋放鎖(同步監視器)
    • 應盡量避免使用suspend()和resume()來控制線程

二、Java常用類

1、字符串相關的類

1.1、字符串相關的類:String

  • String聲明為final的,不可被繼承
  • String實現了Serializable接口:表示字符串是支持序列化的;實現了Comparable接口:表示String可以比較大小
  • String內部定義了final char[] value用于存儲字符串數據
  • String:代表不可變的字符序列。簡稱:不可變性。
    • 1、當對字符串重新賦值時,需要重新指定內存區域賦值,不能使用原有的value進行賦值。
    • 2、當對現有的字符串進行連接操作時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值
    • 3、當調用String的replace()方法修改指定字符或字符串時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值
  • 通過字面量的方式(區別于new)給一個字符串賦值,此時的字符串聲明在字符串常量池中
  • 字符串常量池中是不會存儲相同內容的字符串的
/*** String的實例化方式* 方式一:通過字面量定義的方式* 方式二:通過new + 構造器的方式** 面試題:String s = new String("abc");方式創建對象,在內存中創建了幾個對象?* 答:兩個:一個是堆空間中new結構,另一個是char[]對應的常量池中的數據:"abc"*/ @Test public void test() {// 通過字面量定義的方式:此時的s1和s2的數據javaEE聲明在方法區中的字符串常量池中。String s1 = "javaEE";String s2 = "javaEE";// 通過new + 構造器的方式:此時的s3和s4保存的地址值,是數據在堆空間中開辟空間以后對應的地址值String s3 = new String("javaEE");String s4 = new String("javaEE");System.out.println(s1 == s2);// trueSystem.out.println(s1 == s3);// falseSystem.out.println(s1 == s4);// falseSystem.out.println(s3 == s4);// false };
  • 常量與常量的拼接結果在常量池。且常量池中不會存在相同內容的常量。
  • 只要其中有一個是變量,結果就在堆中。
  • 如果拼接的結果是調用intern()方法,返回值就在常量池中
String s1 = "hello"; String s2 = "world"; String s3 = "hello" + "world"; String s4 = s1 + "world"; String s5 = s1 + s2; String s6 = (s1 + s2).intern(); final String s7 = "hello"; // 此時的s7是一個常量 String s8 = s7 + "world";System.out.println(s3 == s4);// false System.out.println(s3 == s5);// false System.out.println(s4 == s5);// false System.out.println(s3 == s6);// true System.out.println(s3 == s8);// true

1.2、字符串相關的類:String常用方法

  • int length():返回字符串的長度:return value.length
  • char charAt(int index):返回某索引處的字符return value[index]
  • boolean isEmpty():判斷是否是空字符串:return value.length == 0
  • String toLowerCase():使用默認語言環境,將String中的所有字符轉換為小寫
  • String toUpperCase():使用默認語言環境,將String中的所有字符轉換為大寫
  • String trim():返回字符串的副本,忽略首部空白和尾部空白
  • boolean equals(Object obj):比較字符串的內容是否相同
  • boolean equalsIgnoreCase(String anotherString):與equals方法類似,忽略大小寫
  • String concat(String str):將指定字符串連接到此字符串的結尾。等價于用"+"
  • int compareTo(String anotherString):比較兩個字符串的大小
  • String substring(int beginIndex):返回一個新的字符串,它是此字符串從beginIndex開始截取到最后的一個子字符串
  • String substring(int beginIndex, int endIndex):返回一個新的字符串,它是此字符串從beginIndex開始截取到endIndex(不包含)的一個子字符串
  • boolean endsWith(String suffix):測試此字符串是否以指定的后綴結束
  • boolean startsWith(String prefix):測試此字符串是否以指定的前綴開始
  • boolean startsWith(String prefix, int toffset):測試此字符串從指定索引開始的子字符串是否以指定的前綴開始
  • boolean contains(CharSequence s):當且僅當此字符串包含指定的char值序列時,返回true
  • int indexOf(String str):返回指定子字符串在此字符串中第一次出現處的索引
  • int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始
  • int lastIndexOf(String str):返回指定子字符串在此字符串中最右邊出現處的索引
  • int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出現處的索引,從指定的索引開始反向搜索
  • String replace(char oldChar, char new Char):返回一個新的字符串,它是通過用newChar替換此字符串中出現的所有oldChar得到的
  • String replace(CharSequence target, CharSequence replacement):使用指定的字面值替換序列替換此字符串所有匹配字面值目標序列的子字符串
  • String replaceAll(String regex, String replacement):使用給定的replacement替換此字符串所有匹配給定的正則表達式的子字符串
  • String replaceFirst(String regex, String replacement):使用給定的replacement替換此字符串匹配給定的正則表達式的第一個子字符串
  • boolean matches(String regex):告知此字符串是否匹配給定的正則表達式
  • String[] split(String regex):根據給定正則表達式的匹配拆分此字符串
  • String[] split(String regex, int limit):根據匹配給定的正則表達式來拆分此字符串,最多不超過limit個,如果超過了,剩下的全部都放到最后一個元素中

1.3、String與基本數據類型、包裝類之間的轉換

  • String --> 基本數據類型、包裝類:調用包裝類的靜態方法:parseXxx(str)
  • 基本數據類型、包裝類 --> String:調用String重載的valueOf(xxx)

1.4、String與char[]之間的轉換

  • String --> char[]:調用String的toCharArray()
  • char[] --> String:調用String的構造器

1.5、String與byte[]之間的轉換

  • String --> byte[]:調用String的getBytes()
  • byte[] --> String:調用String的構造器

1.6、String、StringBuffer、StringBuilder三者的異同?

  • String:不可變的字符序列;底層使用final char[]存儲
  • StringBuffer:可變的字符序列;線程安全的,效率低;底層使用char[]存儲
  • StringBuilder:可變的字符序列;JDK 5.0新增的,線程不安全的,效率高;底層使用char[]存儲

1.7、StringBuffer源碼分析

  • 擴容問題:如果要添加的數據底層數組盛不下了,那就需要擴容底層的數組。默認情況下,擴容為原來容量的2倍+2,同時將原有數組中的元素復制到新的數組中
  • 指導意義:開發中建議大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
String str = new String(); // char[] value = new char[0]; String str1 = new String("abc"); // char[] value = new char[]{'a','c','c'};StringBuffer sb1 = new StringBuffer(); // char[] value = new char[16];底層創建了一個長度是16的數組 System.out.println(sb1.length()); //0 sb1.append('a');//value[0] = 'a'; sb1.append('b');//value[1] = 'b';StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];

1.8、StringBuffer類的常用方法

  • StringBuffer append(xxx):提供了很多的append()方法,用于進行字符串拼接
  • StringBuffer delete(int start, int end):刪除指定位置的內容
  • StringBuffer replace(int start, int end, String str):把[start, end)位置替換為str
  • StringBuffer insert(int offset, xxx):在指定位置插入xxx
  • StringBuffer reverse():把當前字符序列逆轉

1.9、對比String、StringBuffer、StringBuilder三者的效率

  • 從高到低排列:StringBuilder > StringBuffer > String

1.10、String與StringBuffer、StringBuilder之間的轉換

  • String --> StringBufferr、StringBuilder:調用StringBuffer、StringBuilder構造器
  • StringBufferr、StringBuilder --> String:
    • 調用String構造器
    • StringBuffer、StringBuilder的toString()

2、JDK 8之前的日期時間API

2.1、java.lang.System類

  • System類提供的public static long currentTimeMillis()用來返回當前時間與1970年1月1日0時0分0秒之間以毫秒為單位的時間差。

2.2、java.util.Date類

  • 表示特定的瞬間,精確到毫秒
  • 構造器:
    • Date():使用無參構造器創建的對象可以獲取本地當前時間
    • Date(long date)
  • 常用方法
    • getTime():返回自1970年1月1日 00:00:00 GMT 以來此Date對象表示的毫秒數
    • toString():把此Date對象轉換為以下的形式的String:dow mon dd hh:mm:ss zzz yyyy

2.3、java.text.SimpleDateFormat類

  • Date類的API不易于國際化,大部分被廢棄了,java.text.SimpleDateFormat類是一個不與語言環境有關的方式來格式化和解析日期的具體類
  • 格式化:
    • SimpleDateFormat():默認的模式和語言環境創建對象
    • public SimpleDateFormat(String pattern):該構造方法可以用參數pattern指定的格式創建一個對象
    • public String format(Date date):格式化時間對象date
  • 解析:
    • public Date parse(String source):從給定字符串的開始解析文本,以生成一個日期

2.4、java.util.Calendar類

  • Calendar是一個抽象基類,主要用于完成日期字段之間相互操作的功能
  • 獲取Calendar實例的方法
    • 使用Calendar.getInstance()方法
    • 調用它的子類GregorianCalendar的構造器
  • 一個Calendar的實例是系統時間的抽象表示,通過get(int field)方法來取得想要的時間信息。比如YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY、MINUTE、SECOND
    • public void set(int field, int value)
    • public void add(int field, int amount)
    • public final Date getTime()
    • public final void setTime(Date date)
  • 注意
    • 獲取月份時:一月是0,二月是1,以此類推,12月是11
    • 獲取星期時:周日是1,周一是2,以此類推,周六是7

3、JDK 8中新日期時間API

3.1、新日期時間API出現的原因

  • 可變性:像日期和時間這樣的類應該是不可變的
  • 偏移性:Date中的年份是從1900開始的,而月份都是從0開始
  • 格式化:格式化只對Date有用,Calender則不行
  • 此外,它們都不是線程安全的;不能處理閏秒等

3.2、LocalDate、LocalTime、LocalDateTime類

  • 它們的實例是不可變的對象,分別表示使用ISO-8601日歷系統的日期、時間、日期和時間。
  • 創建方法:
    • now() / now(ZoneId zone):靜態方法,根據當前時間創建對象/指定時區的對象
    • of():靜態方法,根據指定日期/時間創建對象
  • get類的方法:
    • getDayOfMonth()/getDayOfYear():獲得月份天數(1-31)/獲得年份天數(1-366)
    • getDayOfWeek():獲得星期幾(返回一個DayOfWeek枚舉值)
    • getMonth():獲得月份,返回一個Month枚舉值
    • getMonthValue()/getYear():獲得月份(1-12)/獲得年份
    • getHour()/getMinute()/getSecond():獲得當前對象對應的小時、分鐘、秒
  • set類的方法:
    • withDayOfMonth()/withDayOfYear()/withMonth()/withYear():將月份天數、年份天數、月份、年份修改為指定的值并返回新的對象
  • 操作類的方法:
    • plusDays()/plusWeeks()/plusMonths()/plusYears()/plusHours():向當前對象添加幾天、幾周、幾個月、幾年、幾小時
    • minusMonths()/minusWeeks()/minusDays()/minusYears()/minusHours():從當前對象減去幾月、幾周、幾天、幾年、幾小時

3.3、瞬時:Instant

  • 時間線上的一個瞬時點,同樣的,在Java中也是從1970年開始,但以毫秒為單位
  • 常用方法:
    • now():靜態方法,返回默認UTC時區的Instant類的對象
    • ofEpochMilli(long epochMilli):靜態方法,返回在1970-01-01 00:00:00基礎上加上指定毫秒數之后的Instant類的對象
    • atOffset(ZoneOffset offset):結合即時的偏移來創建一個OffsetDateTime
    • toEpochMilli():返回1970-01-01 00:00:00到當前時間的毫秒數,即為時間戳

3.4、java.time.format.DateTimeFormatter類

  • 預定義的標準格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
  • 本地化相關的格式。如ofLocalizedDateTime(FormatStyle.LONG)
  • 自定義的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss E”)
  • 常用方法:
    • ofPattern(String pattern):靜態方法,返回一個指定字符串格式的DateTimeFormatter
    • format(TemporalAccessor t):格式化一個日期、時間,返回字符串
    • parse(CharSequence test):將指定格式的字符序列解析為一個日期、時間

4、Java比較器

4.1、方式一:自然排列:java.lang.Comparable

  • Comparable接口強行對實現它的每個類的對象進行整體排序。這種排序被稱為類的自然排序
  • 實現Comparable的類必須實現compareTo(Object obj)方法,兩個對象即通過compareTo(Object obj)方法的返回值來比較大小。
    • 如果當前對象this大于形參對象obj,則返回正整數
    • 如果當前對象this小于形參對象obj,則返回負整數
    • 如果當前對象this等于形參對象obj,則返回零
  • 實現Comparable接口的對象列表(和數組)可以通過Collections.sort或Arrays.sort進行自動排列。

4.2、方式二:定制排序:java.util.Comparator

  • 當元素的類型沒有實現java.lang.Comparable接口而又不方便修改代碼,或者實現了java.lang.Comparable接口的排序規則不適合當前的操作,那么可以考慮使用Comparator的對象來排序
  • 重寫compare(Object o1, Object o2)方法,比較o1和o2的大小
    • 如果方法返回正整數,表示o1大于o2
    • 如果方法返回0,表示相等
    • 返回負整數,表示o1小于o2
  • 可以將Comparator傳遞給sort方法(如Collections.sort或Arrays.sort),從而允許在排序順序上實現精確控制

5、System類

  • System類代表系統,系統級的很多屬性和控制方法都放置在該類的內部。
  • 成員變量:
    • in:標準輸入流(鍵盤輸入)
    • out:標準輸出流(顯示器)
    • err:標準錯誤輸出流(顯示器)
  • 成員方法:
    • native long currentTimeMillis():該方法的作用是返回當前的計算機時間,時間的表達格式為當前計算機時間和GMT時間(格林威治時間)1970年1月1日0時0分0秒所差的毫秒數。
    • void exit(int status):該方法的作用是退出程序。其中status的值為0代表正常退出,非零代表異常退出。
    • void gc():該方法的作用是請求系統進行垃圾回收。至于系統是否立刻回收,則取決于系統中垃圾回收算法的實現以及系統執行時的情況。
    • String getProperty(String key):該方法的作用是獲得系統中屬性名為key的屬性對應的值。
      • java.version:java運行時環境版本
      • java.home:java安裝目錄
      • os.name:操作系統的名稱
      • os.version:操作系統的版本
      • user.name:用戶的賬戶名稱
      • user.home:用戶的主目錄
      • user.dir:用戶的當前工作目錄

6、Math類

  • abs:絕對值
  • acos,asin,atan,cos,sin,tan:三角函數
  • sqrt:平方根
  • pow(double a, double b):a的b次冪
  • log:自然對數
  • exp:e為底指數
  • max(double a, double b)
  • min(double a, double b)
  • random():返回0.0到1.0的隨機數
  • long round(double a):double型數據a轉換為long型(四舍五入)
  • toDegrees(double angrad):弧度–>角度
  • toRadians(double angdeg):角度–>弧度

7、BigInteger與BigDecimal

7.1 BigInteger類

  • java.math包的BigInteger可以表示不可變的任意精度的整數
  • 構造器:
    • BigInteger(String val):根據字符串構建BigInteger對象
  • 常用方法:
    • public BigInteger abs():返回此BigInteger的絕對值的BigInteger
    • BigInteger add(BigInteger val):返回其值為(this+val)的BigInteger
    • BigInteger subtract(BigInteger val):返回其值為(this-val)的BigInteger
    • BigInteger multiply(BigInteger val):返回其值為(this*val)的BigInteger
    • BigInteger divide(BigInteger val):返回其值為(this/val)的BigInteger。整數相除只保留整數部分
    • BigInteger remainder(BigInteger val):返回其值為(this%val)的BigInteger
    • BigInteger[] divideAndRemainder(BigInteger val):返回包含(this/val)后跟(this%val)的兩個BigInteger的數組
    • BigInteger pow(int exponent):返回其值為(this的exponent次方)的BigInteger

7.2 BigDecimal類

  • BigDecimal類支持不可變的、任意精度的有符號十進制定點數
  • 構造器:
    • public BigDecimal(double val)
    • public BigDecimal(String val)
  • 常用方法:
    • public BigDecimal add(BigDecimal augend)
    • public BigDecimal subtract(BigDecimal subtrahend)
    • public BigDecimal multiply(BigDecimal multiplicand)
    • public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

三、枚舉類&注解

1、枚舉類的使用

1.1、枚舉類的使用

  • 枚舉類的理解:類的對象只有有限個,確定的。我們稱此類為枚舉類
  • 當需要定義一組常量時,強烈建議使用枚舉類
  • 如果枚舉類中只有一個對象,則可以作為單例模式的實現方式

1.2、如何定義枚舉類

  • 方式一:jdk 5.0之前,自定義枚舉類
public class Season {// 1、聲明Seaon對象的屬性:private final修飾private final String seasonName;private final String seasonDesc;// 2、私有化類的構造器,并給對象屬性賦值private Season(String seasonName, String seasonDesc) {this.seasonName = seasonName;this.seasonDesc = seasonDesc;}// 3、提供當前枚舉類的多個對象:public static final的public static final Season SPRING = new Season("春天", "春暖花開");public static final Season SUMMER = new Season("夏天", "夏日炎炎");public static final Season AUTUMN = new Season("秋天", "秋高氣爽");public static final Season WINTER = new Season("冬天", "冬日可愛"); }
  • 方式二:jdk 5.0,可以使用enum關鍵字定義枚舉類
  • 定義的枚舉類默認繼承于java.lang.Enum類
interface Info {void show(); }// 使用enum關鍵字枚舉類 public enum Season1 implements Info{// 1、提供當前枚舉類的對象,多個對象之間用","隔開,末尾對象用";"結束SPRING("春天", "春暖花開") {@Overridepublic void show() {}},SUMMER("夏天", "夏日炎炎") {@Overridepublic void show() {}},AUTUMN("秋天", "秋高氣爽") {@Overridepublic void show() {}},WINTER("冬天", "冬日可愛") {@Overridepublic void show() {}};// 2、聲明Season對象的屬性:private final修飾private final String seasonName;private final String seasonDesc;// 3、私有化類的構造器,并給對象屬性賦值private Season1(String seasonName, String seasonDesc) {this.seasonName = seasonName;this.seasonDesc = seasonDesc;}// 一般都是各個枚舉類對象分別實現接口,不推薦在類中實現抽象方法// @Override// public void show() {//// } }

1.3、Enum類的主要方法

  • value():返回枚舉類型的對象數組。該方法可以很方便地遍歷所有的枚舉類
  • valueOf(String str):可以把一個字符串轉為對應的枚舉類對象。要求字符串必須是枚舉類對象的"名字"。如不是,會有運行時異常:illegalArgumentException
  • toString():返回當前枚舉類對象常量的名稱

2、注解的使用

2.1、注解的概述

  • 從JDK 5.0開始,Java增加了對元數據的支持,也就是Annotation(注解)
  • Annotation其實就是代碼里的特殊標記,這些標記可以在編譯、類加載、運行時被讀取,并執行相應的處理。通過使用Annotation,程序員可以在不改變原有邏輯的情況下,在源文件中嵌入一些補充信息。
  • 框架 = 注解 + 反射 + 設計模式

2.2、常見的Annotation示例

  • 示例一:生成文檔相關的注解
  • 示例二:在編譯時進行格式檢查(JDK內置的三個基本注解)
    • @Override:限定重寫父類方法,該注解只能用于方法
    • @Deprecated:用于表示所修飾的元素(類,方法等)已過時。通常是因為所修飾的結構危險或存在更好的選擇
    • @SuppressWarnings:抑制編譯器警告
  • 示例三:跟蹤代碼依賴性,實現代替配置文件功能

2.3、如何自定義注解:參照@SuppressWarnings定義

  • 注解聲明為:@interface
  • 內部定義成員,通常使用value表示
  • 可以指定成員的默認值,使用default定義
  • 如果自定義注解沒有成員,表明是一個標識作用
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface MyAnnotation {// 多個參數:此時的value是個成員,不是方法String[] value();// 單個參數:如果有默認值,則如此定義// String value() default "Hello"; }
  • 如果注解有成員,在使用注解時,需要指明成員的值
  • 自定義注解必須配上注解的信息處理流程(使用反射)才有意義
  • 自定義注解通常都會指明兩個元注解:Retention、Target

2.4、JDK提供的4種元注解

  • 元注解:對現有的注解進行解釋說明的注解
  • Retention:指定所修飾的Annotation的生命周期:SOURCE\CLASS(默認值)\RUNTIME,只有聲明為RUNTIME生命周期的注解,才能通過反射獲取
  • Target:用于指定被修飾的Annotation能用于修飾哪些程序元素
  • Documented:表示所修飾的注解在被javadoc解析時,保留下來
  • Inherited:被它修飾的Annotation將具有繼承性

2.5、JDK 8中注解的新特性:可重復注解、類型注解

  • 可重復注解:
    • 在MyAnnotation上聲明@Repeatable,成員值為MyAnnotations.class
    • MyAnnotation的Target和Retention等元注解與MyAnnotations相同
  • 類型注解:
    • ElementType.TYPE_PARAMETER:表示該注解能寫在類型變量的聲明語句中(如:泛型聲明)
    • ElementType.TYPE_USE:表示該注解能寫在使用類型的任何語句中
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface MyAnnotations {MyAnnotation[] value(); }@Repeatable(MyAnnotations.class) @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface MyAnnotation {String value1() default "Hello"; }

四、Java集合

1、Java集合框架概述

1.1、集合框架的概述

  • 集合、數組都是對多個數據進行存儲操作的結構,簡稱Java容器。
  • 說明:此時的存儲,主要指的是內存層面的存儲,不涉及到持久化的存儲
  • 數組在存儲多個數據方面的特點:
    • 一旦初始化以后,其長度就確定了
    • 數組一旦定義好,其元素的類型也就確定了。我們也就只能操作指定類型的數據了。比如:String[] arr;int[] arr1;Object[] arr2;
  • 數組在存儲多個數據方面的缺點:
    • 一旦初始化以后,其長度就不可修改
    • 數組中提供的方法非常有限,對于添加、刪除、插入數據等操作,非常不便,同時效率不高。
    • 獲取數組中實際元素的個數的需求,數組沒有現成的屬性或方法可用。
    • 數組存儲數據的特點:有序、可重復。對于無序、不可重復的需求,不能滿足。

1.2、集合框架

  • Coolection接口:單列集合,用來存儲一個一個的對象
    • List接口:存儲有序的、可重復的數據
      • ArrrayList、LinkedList、Vector
    • Set接口:存儲無序的、不可重復的數據
      • HashSet、LinkedHashSet、TreeSet
  • Map接口:雙列集合,用來存儲一對(key-value)一對的數據
    • HashMap、LinkedHashMap、TreeMap、Hashtable、Properties

2、Collection接口方法

  • 添加
    • add(Object obj)
    • addAll(Conllection coll)
  • 獲取有效元素的個數
    • int size()
  • 清空集合
    • void clear()
  • 是否是空集合
    • boolean isEmpty()
  • 是否包含某個元素
    • boolean contains(Object obj):是通過元素的equals方法來判斷是否是同一個對象
    • boolean containsAll(Collection c):也是調用元素的equals方法來比較的。拿兩個集合的元素挨個比較。
  • 刪除
    • boolean remove(Object obj):通過元素的equals方法判斷是否是要刪除的那個元素。只會刪除找到的第一個元素
    • boolean removeAll(Collection coll):取當前集合的差集
  • 取兩個集合的交集
    • boolean retainAll(Collection c):把交集的結果存在當前集合中,不影響c
  • 集合是否相等
    • boolean equals(Object obj)
  • 轉成對象數組
    • Object[] toArray()
  • 獲取集合對象的哈希值
    • hashCode()
  • 遍歷
    • iterator():返回迭代器對象,用于集合遍歷

拓展:數組 --> 集合:調用Arrays類的靜態方法asList()

List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"}); System.out.println(list); // Arrays.asList會優先將其當做一個元素,而不會自動裝箱當做是兩個元素 List arr1 = Arrays.asList(new int[]{123, 456}); System.out.println(arr1.size()); // 1List arr2 = Arrays.asList(new Integer[]{123, 456}); System.out.println(arr2.size());// 2 // 推薦寫法:避免錯誤 List arr3 = Arrays.asList(123, 456); System.out.println(arr3.size()); // 2

3、Iterator迭代器接口

3.1、Iterator迭代器概述

  • Iterator對象稱為迭代器,主要用于遍歷Collection集合中的元素
  • GOF給迭代器模式的定義為:提供一種方法訪問一個容器(container)對象中各個元素,而又不需暴露該對象的內部細節。迭代器模式,就是為容器而生。

3.1、Iterator的使用

  • 內部的方法:hasNext()和next()
  • 集合對象每次調用iterator()方法都得到一個全新的迭代器對象
  • 內部定義了remove(),可以在遍歷的時候,刪除集合中的元素。如果還未調用next()或在上一次調用next方法之后已經調用了remove方法,再調用remove會報IllegalStateException
Iterator iterator = coll.iterator(); // hasNext():判斷是否還有下一個元素 while (iterator.hasNext()) {// next():1、指針下移;2、將下移以后集合位置上的元素返回System.out.println(iterator.next()); }

foreach遍歷集合時,內部仍然調用了迭代器

4、Conllection子接口一:List

4.1、List框架

  • Collection接口:單列集合,用來存儲一個一個的對象
    • List接口:存儲有序的、可重復的數據
      • ArrayList:作為List接口的主要實現類:線程不安全,效率高;底層使用Object[] elementData存儲
      • LinkedList:對于頻繁的插入、刪除操作,使用此類效率比ArrayList高;底層使用雙向鏈表存儲
      • Vector:作為List接口的古老實現類;線程安全的,效率低;底層使用Object[] elementData存儲

4.2、ArrayList的源碼分析

  • ArrayList的源碼分析
/*** 1、JDK 7情況下* ArrayList list = new ArrayList();//底層創建了長度是10的Object[]數組elementData* list.add(123);//elementData[0] = new Integer(123);* ...* list.add(11);如果此次的添加導致底層elementData數組容量不夠,則擴容。* 默認情況下,擴容為原來的容量的1.5倍,同時需要將原有數組中的數據復制到新的數組中** 結論:建議開發中使用帶參的構造器:ArrayList list = new ArrayList(int capacity)** 2、JDK 8中ArrayList的變化:* ArrayList list = new ArrayList();//底層Object[] elementData初始化為{}.并沒有創建長度是10的Object[]數組elementData** list.add(123);//第一次調用add()時,底層才創建了長度10的數組,并將數據123添加到elementData[0]* ...* 后續的添加和擴容操作與JDK 7無異** 3、小結:JDK 7中的ArrayList的對象的創建類似于單例的餓漢式,而JDK 8中的ArrayList的對象* 的創建類似于單例的懶漢式,延遲了數組的創建,節省內存。*/
  • LinkedList的源碼分析
/*** LinkedList list = new LinkedList(); 內部聲明了Node類型的first和last屬性,默認值為null* list.add(123);//將123封裝到Node中,創建了Node對象。* * 其中,Node的定義:體現了LinkedList的雙向鏈表的說法* private static class Node<E> {* E item;* Node<E> next;* Node<E> prev;** Node(Node<E> prev, E element, Node<E> next) {* this.item = element;* this.next = next;* this.prev = prev;* }* }*/
  • Vector的源碼分析:JDK 7和JDK 8中通過Vector()構造器創建對象時,底層都創建了長度為10的數組,在擴容方面,默認擴容為原來數組長度的2倍。

4.3、面試題:ArrayList、LinkedList、Vector三者的異同?

  • 同:三個類都是實現了List接口,存儲數據的特點相同:存儲有序的、可重復的數據
  • 不同:見4.1、List框架

4.4、List接口方法

  • List除了從Collection集合繼承的方法外,List集合里添加了一些根據索引來操作集合元素的方法
  • void add(int inde, Object ele):在index位置插入ele元素
  • boolean addAll(int index, Collection eles):從index位置開始將eles中所有元素添加進來
  • Object get(int index):獲取指定index位置的元素
  • int indexOf(Object obj):返回obj在集合中首次出現的位置
  • int lastIndexOf(Object obj):返回obj在當前集合中末次出現的位置
  • Object remove(int index):移除指定index位置的元素,并返回此元素
  • Object set(int index, Object ele):設置指定index位置的元素為ele
  • List subList(int fromIndex, int toIndex):返回從fromIndex到toIndex位置的子集合
/*** 區分List中remove(int index)和remove(Object obj)*/ @Test public void testListRemove() {List list = new ArrayList();list.add(1);list.add(2);list.add(3);updateList(list);// updateList1(list);System.out.println(list); }private void updateList(List list) {// 注意區分是調用下標還是對象的remove方法// list.remove(2); // [1, 2]// list.remove(new Integer(2)); // [1, 3] }private void updateList1(Collection coll) {// 多態,此時父類只有remove(Object obj)的方法coll.remove(2); // [1, 3] }

5、Conllection子接口二:Set

5.1、Set接口的框架

  • Collection接口:單列集合,用來存儲一個一個的對象
    • Set接口:存儲無序的,不可重復的數據
      • HashSet:作為Set接口的主要實現類:線程不安全;可以存儲null值
        • LinkedHashSet:作為HashSet的子類;遍歷其內部數據時,可以按照添加的順序進行遍歷。對于頻繁的遍歷操作,LinkedHashSet效率高于HashSet
      • TreeSet:可以按照添加對象的指定屬性,進行排序

Set接口中沒有額外定義新的方法,使用的都是Collection中聲明過的方法。

5.2、無序性與不可重復性(HashSet為例)

  • 無序性:不等于隨機性。存儲的數據在底層數組中并非按照數組索引的順序添加,而是根據數據的哈希值決定的。
  • 不可重復性:保證添加的元素按照equals()判斷時,不能返回true。即:相同的元素只能添加一個。
    • 前提是哈希值相同,才會進行equals()判斷

5.3、HashSet的源碼分析

  • 我們向HashSet中添加元素a,首先調用元素a所在類的hashCode()方法,計算元素a的哈希值,此哈希值接著通過某種算法計算出在HashSet底層數組中的存放位置(即為:索引位置),判斷數組此位置上是否已經有元素:
    • 如果此位置上沒有其他元素,則元素a添加成功。 —> 情況1
    • 如果此位置上有其他元素b(或以鏈表形式存在的多個元素),則比較元素a與元素b的hash值:
      • 如果hash值不相同,則元素a添加成功。 —> 情況2
      • 如果hash值相同,進而需要調用元素a所在類的equals()方法:
        • equals()返回true,元素a添加失敗
        • equals()返回false,則元素a添加成功。 —> 情況3
  • 對于添加成功的情況2和情況3而言:元素a與已經存在指定索引位置上數據以鏈表的方式存儲。
    • JDK 7:元素a放在數組中,指向原來的元素。
    • JDK 8:原來的元素在數組中,指向元素a
    • 總結:七上八下
  • HashSet底層:數組+鏈表的結構

要求:向Set中添加的數據,其所在的類一定要重寫hashCode()和equals()。
要求:重寫的hashCode()和equals()盡可能保持一致性:相等的對象必須具有相等的散列碼。重寫兩個方法的小技巧:對象中用作equals()方法比較的Field,都應該用來計算hashCode值

HashSet set = new HashSet(); // Person類中重寫了hashCode()和equals()方法 Person p1 = new Person(1001, "AA"); Person p2 = new Person(1002, "BB");set.add(p1); set.add(p2); System.out.println(set); // [Person{id=1002, name='BB'}, Person{id=1001, name='AA'}] p1.name = "CC"; set.remove(p1); System.out.println(set); // [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}] set.add(new Person(1001, "CC")); System.out.println(set); // [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}] set.add(new Person(1001, "AA")); System.out.println(set); // [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}][Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]

5.4、為什么用Eclipse/IDEA重寫hashCode方法,有31這個數字?

  • 選擇系數的時候要選擇盡量大的系數。因為如果計算出來的hash地址越大,所謂的“沖突”就越少,查找起來效率也會提高。(減少沖突)
  • 并且31只占用了5bits,相乘造成數據溢出的概率較少。
  • 31可以由i*31==(i<<5)-1表示,現在很多虛擬機里面都有做相關優化。(提高算法效率)
  • 31是一個素數,素數作用就是如果我用一個數字來乘以這個素數,那么最終出來的結果只能被素數本身和被乘數還有1來整除!(減少沖突)

5.5、LinkedHashSet的使用

  • LinkedHashSet作為HashSet的子類,在添加數據的同時,每個數據還維護了兩個引用,記錄此數據前一個數據和后一個數據
  • 優點:對于頻繁的遍歷操作,LinkedHashSet效率高于HashSet

5.5、TreeSet的使用

  • 向TreeSet中添加數據,要求是相同的類的對象
  • 兩種排列方法:自然排序(實現Comparable接口)和定制排序(Comparator)
  • 自然排序中,比較兩個對象是否相同的標準為:compareTo()返回0,不再是equals()
  • 定制排序中,比較兩個對象是否相同的標準為:compare()返回0,不再是equals()

6、Map接口

6.1、Map接口的框架

  • Map:雙列數據,存儲key-value對的數據
    • HashMap:作為Map的主要實現類;線程不安全的,效率高;可以存儲null的key和value
      • LinkedHashMap:保證在遍歷map元素時,可以按照添加的順序實現遍歷。原因:在原有的HashMap底層結構基礎上,添加了一對指針,指向前一個和后一個元素,對于頻繁的遍歷操作,此類執行效率高于HashMap
    • TreeMap:保證按照添加的key-value對進行排序;實現排序遍歷。此時考慮key的自然排序或定制排序。底層使用紅黑樹
    • Hashtable:作為古老的實現類;線程安全的,效率低;不能存儲null的key和value
      • Properties:常用來處理配置文件。key和value都是String類型

HashMap的底層:數組+鏈表(JDK 7及之前)或數組+鏈表+紅黑樹(JDK 8)

6.2、Map結構的理解(以HashMap為例)

  • Map中的key:無序的、不可重復的,使用Set存儲所有的key --> key所在的類要重寫equals()和hashCode()
  • Map中的value:無序的、可重復的,使用Collection存儲所有的value --> value所在的類型要重寫equals()
  • 一個鍵值對:key-value構成了一個Entry對象
  • Map中的entry:無序的、不可重復的,使用Set存儲所有的entry

6.3、HashMap的底層實現原理?(以JDK 7為例)

/*** HashMap map = new HashMap();* 在實例化以后,底層創建了長度是16的一對數組Entry[] table* ...可能已經執行過多次put...* map.put(key1, value1):* 首先,調用key1所在類的hashCode()計算key1哈希值,此哈希值經過某種算法計算以后,得到在Entry數組中的存放位置。* 如果此位置上的數據為空,此時的key1-value1添加成功。 ---> 情況1* 如果此位置上的數據不為空,(意味著此位置上存在一個或多個數據(以鏈表形式)),比較key1和已經存在的一個或多個數據的哈希值:* 如果key1的哈希值與已經存在的數據的哈希值都不相同,此時key1-value1添加成功。 ---> 情況2* 如果key1的哈希值和已經存在的某一個數據(key2-value2)的哈希值相同,繼續比較:調用key1所在類的equals(key2)* 如果equals()返回false:此時key1-value1添加成功。---> 情況3* 如果equals()返回true:使用value1替換value2** 補充:關于情況2和情況3:此時key1-value1和原來的數據以鏈表的方法存儲。** 在不斷的添加過程中,會涉及到擴容問題,當超過臨界值(且要存放的位置非空)時,擴容。默認的擴容方式:擴容為原來容量的2倍,并將原有的數據復制過來。*/
  • JDK 8相較于JDK 7在底層實現方面的不同:
    • 1、new HashMap():底層沒有創建一個長度為16的數組
    • 2、JDK 8底層的數組是:Node[],而非Entry[]
    • 3、首次調用put()方法時,底層創建長度為16的數組
    • 4、JDK 7的底層結構只有:數組+鏈表。JDK 8中底層結構:數組+鏈表+紅黑樹。
      • 形成鏈表時,依舊符合“七上八下”(JDK 7:新的元素指向舊的元素。JDK 8:舊的元素指向新的元素)
      • 當數組的某一個索引位置上的元素以鏈表形式存在的數據個數 > 8 且當前數組的長度 > 64時,此時此索引位置上的所有數據改為使用紅黑樹存儲。

6.4、HashMap源碼中的重要常量

  • DEFAULT_INITIAL_CAPACITY:HashMap的默認值,16
  • DEFAULT_LOAD_FACTOR:HashMap的默認加載因子:0.75
  • threahold:擴容的臨界值,=容器*填充因子:16 * 0.75 => 12
  • TREEIFY_THRESHOLD:Bucket中鏈表長度大于該默認值,轉化為紅黑樹:8
  • MIN_TREEIFY_CAPACITY:桶中的Node被樹化時最小的hash表容量:64

面試題:負載因子值的大小,對HashMap有什么影響?
1、負載因子的大小決定了HashMap的數據密度
2、負載因子越大密度越大,發生碰撞的幾率越高,數組中的鏈表越容易長,造成查詢或插入時的比較次數增多,性能會下降。
3、負載因子越小,就越容易觸發擴容,數據密度也越小,意味著發生碰撞的幾率越小,數組中的鏈表也就越短,查詢和插入時比較的次數也越小,性能會更高。但是會浪費一定的內容空間。而且經常擴容也會影響性能,建議初始化預設大一點的空間
4、按照其他語言的參考及研究經驗,會考慮將負載因子設置在0.7~0.75,此時平均檢索長度接近于常數

6.5、LinkedHashMap的底層原理

  • LinkedHashMap底層使用的結構與HashMap相同,因為LinkedHashMap繼承于HashMap
  • 區別就在于:LinkedHashMap內部提供了Entry,替換HashMap中的Node
  • HashMap中的內部類:Node
static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next; }
  • LinkedHashMap中的內部類:Entry
static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;// 能夠記錄添加的元素的先后順序Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);} }

6.5、Map接口常用方法

  • 添加、刪除、修改操作:
    • Object put(Object key, Object value):指定key-value添加到(或修改)當前map對象中
    • void putAll(Map m):將m中的所有key-value對存放到當前map中
    • Object remove(Object key):移除指定key的key-value對,并返回value
    • void clear():清空當前map中的所有數據
  • 元素查詢的操作:
    • Object get(Object key):獲取指定key對應的value
    • boolean containsKey(Object key):是否包含指定的key
    • boolean containsValue(Object value):是否包含指定的value
    • int size():返回map中key-value對的個數
    • boolean isEmpty():判斷當前map是否為空
    • boolean equals(Object obj):判斷當前map和參數對象obj是否相等
  • 元視圖操作的方法:
    • Set keySet():返回所有key構成的Set集合
    • Collection values():返回所有value構成的Collection集合
    • Set entrySet():返回所有key-value對構成的Set集合

7、Collections工具類

  • Collections是一個操作Set、List和Map等集合的工具類
  • Collections中提供了一系列靜態的方法對集合元素進行排序、查詢和修改等操作,還提供了對集合對象設置不可變、對集合對象實現同步控制等方法
  • 排序操作:(均為static方法)
    • reverse(List):反轉List中元素的順序
    • shuffle(List):對List集合元素進行隨機排序
    • sort(List):根據元素的自然順序對指定List集合元素按升序排序
    • sort(List, Comparator):根據指定的Comparator產生的順序對List集合元素進行排序
    • swap(List, int, int):將指定list集合中的i處元素和j處元素進行交換
  • 查找、替換
    • Object max(Collection):根據元素的自然順序,返回給定集合中的最大值
    • Object max(Collection, Comparator):根據Comparator指定的順序,返回給定集合中的最大元素
    • Object min(Collection)
    • Object min(Collection, Comparator)
    • int frequency(Collection, Object):返回指定集合中指定元素的出現次數
    • void copy(List dest, List src):將src中的內容復制到dest中
    • boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替換List對象的所有舊值
  • 同步控制
    • synchronizedXxx():將指定集合包裝成線程同步的集合,從而可以解決多線程并發訪問集合時的線程安全問題
    • synchronizedList(List list)
    • synchronizedMap(Map map)
List list = new ArrayList(); list.add(123); list.add(43); list.add(765); list.add(-97); list.add(0); // 報異常:java.lang.IndexOutOfBoundsException: Source does not fit in dest // List dest = new ArrayList(); // Collections.copy(dest, list); // The destination list must be at least as long as the source list. // If it is longer, the remaining elements in the destination list are unaffected. List dest = Arrays.asList(new Object[list.size()]); System.out.println(dest.size()); //list.size(); Collections.copy(dest, list); System.out.println(dest);

五、泛型

1、為什么要有泛型

1.1、泛型的概念

  • 所謂泛型,就是允許在定義類、接口時通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數類型。這個類型參數將在使用時(例如,繼承或實現這個接口,用這個類型聲明變量、創建對象時)確定(即傳入實際的類型參數,也稱為類型實參)。

1.2、泛型的引入背景

  • 集合容器類在設計階段/聲明階段不能確定這個容器到底實際存的是什么類型的對象,所以在JDK1.5之前只能把元素類型設計為Object,JDK1.5之后使用泛型來解決。因為這個時候除了元素的類型不確定,其他的部分是確定的,例如關于這個元素如何保存,如何管理等是確定的,因此此時把元素的類型設計成一個參數,這個類型參數叫做泛型。

2、在集合中使用泛型

  • 集合接口或集合類在JDK5.0時都修改為帶泛型的結構
  • 在實例化集合類時,可以指明具體的泛型類型
  • 指明完以后,在集合類或接口中凡是定義類或接口時,內部結構(比如:方法、構造器、屬性等)使用到類的泛型的位置,都指定為實例化的泛型類型
    • 比如:add(E e) —> 實例化以后:add(Integer e)
  • 注意點:泛型的類型必須是類,不能是基本數據類型。需要用到基本數據類型的位置,拿包裝類替換
  • 如果實例化時,沒有指明泛型的類型,默認類型為java.lang.Object類型

3、自定義泛型結構

  • 泛型類可能有多個參數,此時應將多個參數一起放在尖括號內。比如:<E1,E2,E3>
  • 泛型類的構造器如下:public GenericClass(){}
  • 實例化后,操作原來泛型位置的結構必須與指定的泛型類型一致。
  • 泛型不同的引用不能相互賦值
    • 盡管在編譯時ArrayList<String>和ArrayList<Interger>是兩種類型,但是,在運行時只有一個ArrayList被加載到JVM中。
  • 泛型如果不指定,將被擦除,泛型對應的類型均按照Object處理,但不等價于Object。經驗:泛型要使用一路都用。要不用,一路都不要用。
  • 如果泛型結構是一個接口或抽象類,則不可以創建泛型類的對象
  • JDK1.7,泛型的簡化操作:ArrayList<Fruit> flist = new ArrayList<>();
  • 泛型的指定中不能使用基本數據類型,可以使用包裝類替換
  • 在類/接口上聲明的泛型,在本類或本接口中即代表某種類型,可以作為非靜態屬性的類型、非靜態方法的參數類型、非靜態方法的返回值類型。但在靜態方法中不能使用類的泛型。
  • 異常類不能是泛型的
  • 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity];
  • 父類有泛型,子類可以選擇保留泛型也可以選擇指定泛型類型:
    • 子類不保留父類的泛型:按需實現
      • 沒有類型,擦除
      • 具體類型
    • 子類保留父類的泛型:泛型子類
      • 全部保留
      • 部分保留
/*** 自定義泛型類* @param <T>*/ public class Order<T> {private String orderName;private int orderId;//類的內部結構就可以使用類的泛型private T orderT;public Order() {}public Order(String orderName, int orderId, T orderT) {this.orderName = orderName;this.orderId = orderId;this.orderT = orderT;}public T getOrderT() {return orderT;}public void setOrderT(T orderT) {this.orderT = orderT;}// 泛型方法:在方法中出現了泛型的結構,泛型參數與類的泛型參數沒有任何關系// 換句話說,泛型方法所屬的類是不是泛型類都沒有關系public <E> List<E> copyFormArrayToList(E[] arr) {ArrayList<E> list = new ArrayList<>();for (E e : arr) {list.add(e);}return list;} // 泛型方法,可以聲明為靜態的。原因:泛型參數是在調用方法時確定的。并非在實例化類時確定的。public static <E> List<E> copyFormArrayToList1(E[] arr) {} } class Fatherr<T1, T2> {} // 子類不保留父類的泛型 // 1、沒有類型,擦除 class Son1<A, B> extends Father {//等價于 class Son extends Father<Object, Object> } // 2、具體類型 class Son2<A, B> extends Father<Ineger, String> {} // 子類保留父類的泛型 // 1、全部保留 class Son3<T1, T2, A, B> extends Father<T1, T2> {} // 2、部分保留 class Son4<T2, A, B> extends Father<T1, T2> {}

4、泛型在繼承上的體現

  • 雖然類A是類B的父類,但是G<A>和G<B>二者不具備子父類關系,二者是并列關系
    • 補充:類A是類B的父類,A<G>是B<G>的父類

5、通配符的使用

  • 使用類型通配符:?
    • List<?>是List<String>、List<Object>等各種泛型List的父類
  • 讀取List<?>的對象list中的元素時,永遠是安全的,因為不管list的真實類型是什么,它包含的都是Object
  • 寫入list中的元素時,不行。因為我們不知道元素類型,不能向其中添加對象。
    • 唯一的例外是null,它是所有類型的成員
@Test public void test() {List<?> list = null;List<String> list1 = new ArrayList<>();list1.add("AA");list1.add("BB");list1.add("CC");print(list1);list = list1;// 添加:對于List<?>不能向其內部添加數據// list.add("AA");// list.add("?");// 除了添加nulllist.add(null);//獲取(讀取):允許讀取數據,讀取的數據類型為ObjectObject o = list.get(0);System.out.println(o); }public void print(List<?> list) {Iterator<?> iterator = list.iterator();while (iterator.hasNext()) {Object obj = iterator.next();System.out.println(obj);} }
  • <? extentds A> (無窮小, A]
    • 只允許泛型為A及A子類的引用調用
  • <? super A> [A, 無窮大)
    • 只允許泛型為A及A父類的引用調用

六、IO流

1、File類的使用

1.1、File類的理解

  • File類的一個對象,代表一個文件或一個文件目錄(俗稱:文件夾)
  • File類聲明在java.io包下
  • File類中涉及到關于文件或文件目錄的創建、刪除、重命名、修改時間、文件大小等方法,并未涉及到寫入或讀取文件內容的操作。如果需要讀取或寫入文件內容,必須使用IO流來完成。
  • 后續File類的對象常會作為參數傳遞到流的構造器中,指明讀取或寫入的“終點”

1.2、File的實例化

  • 常見構造器
    • File(String filePath)
    • File(String parentPath, String childPath)
    • File(File parentFile, String childPath)
  • 路徑的分類
    • 相對路徑:相較于某個路徑下,指明的路徑
    • 絕對路徑:包含盤符在內的文件或文件目錄的路徑
  • 路徑分隔符
    • public static final String separator:根據操作系統,動態的提供分隔符

1.3、常用方法

  • File類的獲取功能
    • public String getAbsolutePath():獲取絕對路徑
    • public String getPath():獲取路徑
    • public String getName():獲取名稱
    • public String getParent():獲取上層文件目錄。若無,返回null
    • public long length():獲取文件長度(即:字節數)。不能獲取目錄的長度。
    • public long lastModified():獲取最后一次的修改時間,毫秒值
    • public String[] list():獲取指定目錄下的所有文件或文件目錄的名稱數組
    • public File[] listFiles():獲取指定目錄下的所有文件或文件目錄的File數組
  • File類的重命名功能
    • public boolean renameTo(File dest):把文件重命名為指定的文件路徑。要想保證返回true,需要源文件在硬盤中存在,且目標文件不能在硬盤中存在
  • File類的判斷功能
    • public boolean isDirectory():判斷是否是文件目錄
    • public boolean isFile():判斷是否是文件
    • public boolean exists():判斷是否存在
    • public boolean canRead():判斷是否可讀
    • public boolean canWrite():判斷是否可寫
    • public boolean isHidden():判斷是否隱藏
  • File類的創建功能
    • public boolean creatNewFile():創建文件。若文件存在,則不創建,返回false
    • public boolean mkdir():創建文件目錄。如果文件目錄存在,就不創建了。如果此文件目錄的上層目錄不存在,也不創建。
    • public boolean mkdirs():創建文件目錄。如果上層文件目錄不存在,一并創建
  • File類的刪除功能
    • public boolean delete():刪除文件或文件夾。要刪除一個文件目錄,請注意該文件目錄內不能包含文件或文件目錄

2、IO原理及流的分類

2.1、流的分類

  • 按操作數據單位不同分為:字節流、字符流
  • 按數據流的流向不同分為:輸入流、輸出流
  • 按流的角色的不同分為:節點流、處理流

2.2、流的體系結構

分類字節輸入流字節輸出流字符輸入流字符輸出流
抽象基類InputStreamOutputStreamReaderWriter
訪問文件FileInputStreamFileOutputStreamFileReaderFileWriter
訪問數組ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
訪問管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter
訪問字符串StringReaderStringWriter
緩沖流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
轉換流InputStreamReaderOutputStreamWriter
對象流ObjectInputStreamObjectOutputStream
FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
打印流PrintStreamPrintWriter
推回輸入流PushbackInputStreamPushbackReader
特殊流DataInputStreamDataOutputStream

2.3、輸入、輸出的標準化過程

  • 輸入過程
    • 創建File類的對象,指明讀取的數據的來源。(要求此文件一定要存在)
    • 創建相應的輸入流,將File類的對象作為參數,傳入流的構造器中
    • 具體的讀入過程
    • 關閉流資源
  • 輸出過程
    • 創建File類的對象,指明寫出的數據的位置。(不要求此文件一定要存在)
    • 創建相應的輸出流,將File類的對象作為參數,傳入流的構造器中
    • 具體的寫出過程
    • 關閉流資源

說明:程序中出現的異常需要使用try-catch-finally處理

3、節點流(或文件流)

3.1、FileReader的使用

  • read()的理解:返回讀入的一個字符。如果達到文件末尾,返回-1
  • 異常的處理:為了保證流資源一定可以執行關閉操作。需要使用try-catch-finally處理
  • 讀入的文件一定要存在,否則就會報FileNotFoundException
@Test public void testFileReader1 () {FileReader fr = null;try {// 1、File類的實例化File file = new File("hello.txt");// 2、FileReader流的實例化fr = new FileReader(file);// 3、讀入的操作// read(char[] cbuf):返回每次讀入cbuf數組中的字符的個數。如果達到文件末尾則返回-1char[] cbuf = new char[5];int len;while ((len = fr.read(cbuf)) != -1) {String str = new String(cbuf, 0, len);System.out.println(str);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fr != null) {// 4、關閉資源try {fr.close();} catch (IOException e) {e.printStackTrace();}}} }

3.2、FileWriter的使用

  • 輸出操作,對應的File可以不存在。并不會報異常
  • File對應的硬盤中的文件如果不存在,在輸出的過程中,會自動創建此文件。
  • File對應的硬盤中的文件如果存在:
    • 如果流使用的構造器是:FileWriter(file, false) / FileWriter(file):對原有文件的覆蓋
    • 如果流使用的構造器是:FileWriter(file, true):不會對原有文件覆蓋,而是在原有文件基礎上追加內容
@Test public void testFileWriter () {FileWriter fw = null;try {// 1、提供File類的對象,指明寫出到的文件File file = new File("hello1.txt");// 2、提供FileWriter的對象,用于數據的寫出fw = new FileWriter(file, false);// 3、寫出的操作fw.write("I have a dream!\n");fw.write("you need to have a dream!");} catch (IOException e) {e.printStackTrace();} finally {// 4、流資源的關閉if (fw != null) {try {fw.close();} catch (IOException e) {e.printStackTrace();}}} }

3.3、文本文件的復制

@Test public void testFileReaderFileWriter () {FileReader fr = null;FileWriter fw = null;try {// 1、創建File類的對象,指明讀入和寫出的文件File srcFile = new File("hello.txt");File destFile = new File("hello2.txt");// 2、創建輸入流和輸出流的對象fr = new FileReader(srcFile);fw = new FileWriter(destFile);// 3、數據的讀入和寫出操作char[] cbuf = new char[5];int len; // 記錄每次讀入到cbuf數組中的字符的個數while ((len = fr.read(cbuf)) != -1) {// 每次寫出len個字符fw.write(cbuf, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {// 4、關閉流資源if (fw != null) {try {fw.close();} catch (IOException e) {e.printStackTrace();}}if (fr != null) {try {fr.close();} catch (IOException e) {e.printStackTrace();}}} }

3.4、FileInputStream/FileOutputStream的使用

  • 對于文本文件(.txt, .java, .c, .cpp),使用字符流處理
  • 對于非文本文件(.jpg, .mp3, .mp4, .avi, .doc, .ppt,…),使用字節流處理
/*** 實現對圖片的復制操作*/ @Test public void testFileInputOutputStream () {FileInputStream fis = null;FileOutputStream fos = null;try {// 1、造文件File srcFile = new File("愛情與友情.jpg");File destFile = new File("愛情與友情2.jpg");// 2、造流fis = new FileInputStream(srcFile);fos = new FileOutputStream(destFile);// 3、復制的過程byte[] buffer = new byte[5];int len;while ((len = fis.read(buffer)) != -1) {fos.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {// 4、關閉流if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}} }

說明:
IDEA中:如果大家開發使用JUnit中的單元測試方法測試,相對路徑即為當前Module下。如果使用main()測試,相對路徑即為當前的Project下。
Eclipse中:不管使用單元測試方法還是使用main()測試,相對路徑都是當前的Project下

4、緩沖流

4.1、緩沖流涉及到的類

  • BufferedInputStream
  • BufferedOutputSteam
  • BufferedReader
  • BufferedWriter

4.2、作用

  • 提高流的讀取、寫入的速度。
  • 提高讀寫速度的原因:內部提供了一個緩沖區。默認情況下是8kb
public class BufferedInputStream extends FilterInputStream {private static int DEFAULT_BUFFER_SIZE = 8192;}

4.3、典型代碼

  • 使用BufferedInputStream和BufferedOutputStream:處理非文本文件
@Test public void copyFileWithBuffered(String srcPath, String destPath) {BufferedInputStream bis = null;BufferedOutputStream bos = null;try {// 1、造文件File srcFile = new File(srcPath);File destFile = new File(destPath);// 2、造流// 2.1、造節點流FileInputStream fis = new FileInputStream(srcFile);FileOutputStream fos = new FileOutputStream(destFile);// 2.2、造緩沖流bis = new BufferedInputStream(fis);bos = new BufferedOutputStream(fos);// 3、復制的細節:讀取、寫入byte[] buffer = new byte[10];int len;while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len);// bos.flush(); //刷新緩沖區}} catch (IOException e) {e.printStackTrace();} finally {// 4、資源關閉// 要求:先關閉外層的流,再關閉內層的流if (bis != null) {try {bis.close();} catch (IOException e) {e.printStackTrace();}}if (bos != null) {try {bos.close();} catch (IOException e) {e.printStackTrace();}}// 說明:關閉外層流的同時,內層流也會自動的進行關閉。關于內層流的關閉,我們可以省略// fos.close();// fis.close();} }
  • 使用BufferedReader和BufferedWriter:處理文本文件
@Test public void testBufferedReaderBufferedWriter () {BufferedReader br = null;BufferedWriter bw = null;try {// 創建文件和相應的流br = new BufferedReader(new FileReader(new File("dbcp.txt")));bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));// 讀寫操作// 方式一:使用char[]數組// char[] cbuf = new char[1024];// int len;// while ((len = br.read(cbuf)) != -1) {// bw.write(cbuf, 0, len);// }// 方式二:使用StringString data;while ((data = br.readLine()) != null) {// 方法一:// bw.write(data + "\n"); // data中不包含換行符// 方法二:bw.write(data);bw.newLine(); // 提供換行的操作}} catch (IOException e) {e.printStackTrace();} finally {// 關閉資源if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}if (bw != null) {try {bw.close();} catch (IOException e) {e.printStackTrace();}}}}

5、轉換流

5.1、轉換流涉及到的類:屬于字符流

  • InputStreamReader:將一個字節的輸入流轉換為字符的輸入流
    • 解碼:字節、字節數組 —> 字符數組、字符串
  • OutputStreamWriter:將一個字符的輸出流轉換為字節的輸出流
    • 編碼:字符數組、字符串 —> 字節、字節數組

說明:編碼決定了解碼的方式

5.2、作用

  • 提供字節流與字符流之間的轉換

5.3、典型實現

  • 文件編碼的方式(比如:GBK),決定了解析時使用的字符集(也只能是GBK)
@Test public void test2 () {InputStreamReader isr = null;OutputStreamWriter osw = null;try {// 1、造文件、造流File file1 = new File("dbcp.txt");File file2 = new File("dbcp_gbk.txt");FileInputStream fis = new FileInputStream(file1);FileOutputStream fos = new FileOutputStream(file2);// isr = new InputStreamReader(fis); // 使用系統默認的字符集isr = new InputStreamReader(fis, "utf-8");osw = new OutputStreamWriter(fos, "gbk");// 2、讀寫過程char[] cbuf = new char[20];int len;while ((len = isr.read(cbuf)) != -1) {osw.write(cbuf, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {// 3、關閉資源if (isr != null) {try {isr.close();} catch (IOException e) {e.printStackTrace();}}if (osw != null) {try {osw.close();} catch (IOException e) {e.printStackTrace();}}} }

5.4、常見的編碼表

  • ASCII:美國標準信息交換碼。用一個字節的7位可以表示。
  • ISO8859-1:拉丁碼、歐洲碼表。用一個字節的8位表示
  • GB2312:中國的中文編碼表。最多兩個字節編碼所有字符
  • GBK:中國的中文編碼表升級,融合了更多的中文文字符號。最多兩個字節編碼
  • Unicode:國際標準碼,融合了目前人類使用的所有字符。為每個字符分配唯一的字符碼。所有的文字都用兩個字節來表示。
  • UTF-8:變長的編碼方法,可用1-4個字節來表示一個字符。

6、其它的流的使用

6.1、標準輸入、輸出流

  • System.in:標準的輸入流,默認從鍵盤輸入
  • System.out:標準的輸出流,默認從控制臺輸出
  • 修改默認的輸入和輸出行為
    • System類的setIn(InputStream is)/setOut(PrintStream ps)方式重新指定輸入和輸出的流

6.2、打印流

  • PrintStream和PrintWriter
  • 提供了一些列重載的print()和println()方法,用于多種數據類型的輸出
  • System.out返回的是PrintStream的實例

6.3、數據流

  • DataInputStream和DataOutputStream
  • 用于讀取或寫出基本數據類型的變量或字符串
@Test public void test3() {DataOutputStream dos = null;try {dos = new DataOutputStream(new FileOutputStream("data.txt"));dos.writeUTF("劉建辰");dos.flush(); // 刷新操作,將內存中的數據寫入文件dos.writeInt(23);dos.flush();dos.writeBoolean(true);dos.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (dos != null) {try {dos.close();} catch (IOException e) {e.printStackTrace();}}} }/*** 注意點:讀取不同類型的數據的順序要與當初寫入文件時,保存的數據的順序一致*/ @Test public void test4() {DataInputStream dis = null;try {dis = new DataInputStream(new FileInputStream("data.txt"));String name = dis.readUTF();int age = dis.readInt();boolean isMale = dis.readBoolean();System.out.println(name);System.out.println(age);System.out.println(isMale);} catch (IOException e) {e.printStackTrace();} finally {if (dis != null) {try {dis.close();} catch (IOException e) {e.printStackTrace();}}} }

7、對象流

7.1、對象流

  • ObjectInputStream:內存中的對象 —> 存儲中的文件、通過網絡傳輸出去(序列化過程)
  • ObjectOutputSteam:存儲中的文件、通過網絡接受過來 —> 內存中的對象(反序列化過程)

7.2、對象的序列化機制

  • 對象序列化機制允許把內存中的Java對象轉換成平臺無關的二進制流,從而允許把這種二進制流持久地保存在磁盤上,或通過網絡將這種二進制流傳輸到另一個網絡節點。
  • 當其它程序獲取了這種二進制流,就可以恢復成原來的Java對象

7.3、序列化代碼實現

@Test public void testObjectOutputSteam () {ObjectOutputStream oos = null;try {// 1、造流oos = new ObjectOutputStream(new FileOutputStream("object.dat"));// 2、讀寫過程oos.writeObject(new String("我愛北京天安門"));oos.flush();} catch (IOException e) {e.printStackTrace();} finally {// 3、關閉資源if (oos != null) {try {oos.close();} catch (IOException e) {e.printStackTrace();}}} }

7.4、反序列化代碼實現

@Test public void testObjectInputSteam () {ObjectInputStream ois = null;try {ois = new ObjectInputStream(new FileInputStream("object.dat"));Object obj = ois.readObject();String str = (String) obj;System.out.println(str);} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {if (ois != null) {try {ois.close();} catch (IOException e) {e.printStackTrace();}}} }

7.5、實現序列化的對象所屬的類需要滿足的條件

  • 需要實現接口:Serializable
  • 當前類提供一個全局常量:serialVersionUID
  • 除了當前類需要實現Serializable接口之外,還必須保證其內部所有屬性也必須是可序列化的。(默認情況下,基本數據類型可序列化)

補充:ObjectOutputSteam和ObjectInputStream不能序列化static和transient修飾的成員變量

8、隨機存取文件流

8.1、隨機存取文件流

  • RandomAccessFile

8.2、使用說明

  • RandomAccessFile直接繼承于java.lang.Object類,實現了DataInput和DataOutput接口
  • RandomAccessFile既可以作為一個輸入流,又可以作為一個輸出流
  • 如果RandomAccessFile作為輸出流時,寫出到的文件如果不存在,則在執行過程中自動創建。如果寫出到的文件存在,則會對原文件內容進行覆蓋。(默認情況下,從頭覆蓋)
  • 可以通過相關的操作,實現RandomAccessFile“插入”數據的效果。seek(int pos)

8.3、典型代碼

/*** 實現復制功能*/ @Test public void test1 () {RandomAccessFile raf1 = null;RandomAccessFile raf2 = null;try {// 1、造流raf1 = new RandomAccessFile(new File("愛情與友情.jpg"), "r");raf2 = new RandomAccessFile(new File("愛情與友情1.jpg"), "rw");// 2、讀寫過程byte[] buffer = new byte[1024];int len;while ((len = raf1.read(buffer)) != -1) {raf2.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {// 3、關閉資源if (raf1 != null) {try {raf1.close();} catch (IOException e) {e.printStackTrace();}}if (raf2 != null) {try {raf2.close();} catch (IOException e) {e.printStackTrace();}}} } /*** 使用RandomAccessFile實現數據的插入效果*/ @Test public void test3 () {RandomAccessFile raf1 = null;try {raf1 = new RandomAccessFile("hello.txt", "rw");raf1.seek(3); // 將指針調到角標為3的位置// 保存指針3后面的所有數據到StringBuilder中StringBuilder buildr = new StringBuilder((int) new File("hello.txt").length());byte[] buffer = new byte[20];int len;while ((len = raf1.read(buffer)) != -1) {buildr.append(new String(buffer, 0, len));}// 調回指針,寫入“xyz”raf1.seek(3);raf1.write("xyz".getBytes());// 將StringBuilder中的數據寫入到文件中raf1.write(buildr.toString().getBytes());} catch (IOException e) {e.printStackTrace();} finally {if (raf1 != null) {try {raf1.close();} catch (IOException e) {e.printStackTrace();}}} }

9、NIO.2中Path、Paths、Files類的使用

9.1、NIO的使用說明

  • Java NIO(New IO, Non-Blocking IO)是從Java 1.4版本開始引入的一套新的IO API,可以替代標準的Java IO API。
  • NIO與原來的IO同樣的作用和目的,但是使用的方式完全不同,NIO支持面向緩沖區的(IO是面向流的)、基于通道的IO操作
  • NIO將以更高效的方式進行文件的讀寫操作
  • 隨著JDK 7的發布,Java對NIO進行了極大的擴展,增強了對文件處理和文件系統特性的支持,以至于我們稱他們為NIO.2

9.2、Path的使用

  • Path替換原有的File類
  • Paths類提供了靜態get()方法用來獲取Path對象:
    • static Path get(String first, String … more):用于將多個字符串串連成路徑
    • static Path get(URI uri):返回指定uri對應的Parh路徑
  • 常用方法:
    • String toString():返回調用Path對象的字符串表示形式
    • boolean startsWith(String path):判斷是否以path路徑開始
    • boolean endsWith(String path):判斷是否以path路徑結束
    • boolean isAbsolute():判斷是否是絕對路徑
    • Path getParent():返回path對象包含整個路徑,不包含Path對象指定的文件路徑
    • Path getRoot():返回調用Path對象的根路徑
    • Path getFileName():返回與調用Path對象關聯的文件名
    • int getNameCount():返回Path根目錄后面元素的數量
    • Path getName(int idx):返回指定索引位置idx的路徑名稱
    • Path toAbsolutePath():作為絕對路徑返回調用Path對象
    • Path resolve(Path p):合并兩個路徑,返回合并后的路徑對應的Path對象
    • File toFile():將Path轉換為File類的對象

9.3、Files工具類

  • 作用:操作文件或文件目錄的工具類
  • 常用方法:
    • Path copy(Path src, Path dest, CopyOption … how):文件的復制
    • Path createDirectory(Path path, FileAttribute<?> … attr):創建一個目錄
    • Path createFile(Path path, FileAttribute<?> … arr):創建一個文件
    • void delete(Path path):刪除一個文件/目錄,如果不存在,執行報錯
    • void deleteIfExists(Path path):Path對應的文件/目錄如果存在,執行刪除
    • Path move(Path src, Path dest, CopyOption … how):將src移動到dest位置
    • long size(Path path):返回指定文件的大小
  • 用于判斷:
    • boolean exists(Path path, LinkOption … opts):判斷文件是否存在
    • boolean isDirectory(Path path, LinkOption … opts):判斷是否是目錄
    • boolean isRegularFile(Path path, LinkOption … opts):判斷是否是文件
    • boolean isHidden(Path path):判斷是否是隱藏文件
    • boolean isReadable(Path path):判斷文件是否可讀
    • boolean isWritable(Path path):判斷文件是否可寫
    • boolean notExists(Path path, LinkOption … opts):判斷文件是否不存在
  • 用于操作內存
    • SeekableByteChannel newByteChannel(Path path, OpenOption … how):獲取與指定文件的連接,how指定打開方式
    • DirectoryStream<Path> newDirectoryStream(Path path):打開path指定的目錄
    • InputStream newInputStream(Path path, OpenOption … how):獲取InputStream對象
    • OutputStream newOutputStream(Path path, OpenOption … how):獲取OutputStream對象

七、網絡編程

1、InetAddress類的使用

1.1、實現網絡通信需要解決的兩個問題

  • 如何準確地定位網絡上一臺或多臺主機;定位主機上的特定的應用
  • 找到主機后如何可靠高效地進行數據傳輸

1.2、網絡通信的兩個要素

  • 對應問題一:IP和端口號
  • 對應問題二:提供網絡通信協議:TCP/IP參考模型(應用層、傳輸層、網絡層、物理+數據鏈路層)

1.3、通信要素一:IP和端口號

  • IP的理解
    • IP:唯一的標識Internet上的計算機(通信實體)
    • 在Java中使用InetAddress類代表IP
    • IP分類:IPv4和IPv6;萬維網和局域網
    • 域名:www.baidu.com、www.mi.com
      • 域名解析:域名容易記憶,當在連接網絡時輸入一個主機的域名后,域名服務器(DNS)負責將域名轉化成IP地址,這樣才能和主機建立連接。
    • 本地回路地址:127.0.0.1 對應著:localhost
  • InetAddress類:此類的一個對象就代表著一個具體的IP地址
    • 實例化:
      • getByName(String host)
      • getLocalHost()
    • 常用方法:
      • getHostName()
      • getHostAddress()
  • 端口號:正在計算機上運行的進程
    • 要求:不同的進程不同的端口號
    • 范圍:被規定為一個16位的整數 0~65535
  • 端口號與IP地址的組合得出一個網絡套接字:Socket

1.4、通信要素二:網絡通信協議

OSI參考模型TCP/IP參考模型TCP/IP參考模型各層對應協議
應用層、表示層、會話層應用層HTTP、FTP、Telnet、DNS…
傳輸層傳輸層TCP、UDP…
網絡層網絡層IP、ICMP、ARP…
數據鏈路層、物理層物理+數據鏈路層Link

1.5、TCP和UDP的區別

  • TCP協議:
    • 使用TCP協議前,須先建立TCP連接,形成傳輸數據通道
    • 傳輸前,采用“三次握手”方式,點對點通信,是可靠的
    • TCP協議進行通信的兩個應用進程:客戶端、服務端
    • 在連接中可進行大數據量的傳輸
    • 傳輸完畢,需要釋放已建立的連接,效率低
  • UDP協議:
    • 將數據、源、目的封裝成數據包,不需要建立連接
    • 每個數據報的大小限制在64K內
    • 發送不管對方是否準備好,接收方收到也不確認,故是不可靠的
    • 可以廣播發送
    • 發送數據結束時無需釋放資源,開銷小,速度快

1.6、TCP三次握手和四次揮手

  • 三次握手
#mermaid-svg-fvFiduDQQxvTter4 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-fvFiduDQQxvTter4 .error-icon{fill:#552222;}#mermaid-svg-fvFiduDQQxvTter4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fvFiduDQQxvTter4 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-fvFiduDQQxvTter4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fvFiduDQQxvTter4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fvFiduDQQxvTter4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fvFiduDQQxvTter4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fvFiduDQQxvTter4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fvFiduDQQxvTter4 .marker.cross{stroke:#333333;}#mermaid-svg-fvFiduDQQxvTter4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fvFiduDQQxvTter4 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fvFiduDQQxvTter4 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-fvFiduDQQxvTter4 .actor-line{stroke:grey;}#mermaid-svg-fvFiduDQQxvTter4 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-fvFiduDQQxvTter4 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-fvFiduDQQxvTter4 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-fvFiduDQQxvTter4 .sequenceNumber{fill:white;}#mermaid-svg-fvFiduDQQxvTter4 #sequencenumber{fill:#333;}#mermaid-svg-fvFiduDQQxvTter4 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-fvFiduDQQxvTter4 .messageText{fill:#333;stroke:#333;}#mermaid-svg-fvFiduDQQxvTter4 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fvFiduDQQxvTter4 .labelText,#mermaid-svg-fvFiduDQQxvTter4 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-fvFiduDQQxvTter4 .loopText,#mermaid-svg-fvFiduDQQxvTter4 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-fvFiduDQQxvTter4 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fvFiduDQQxvTter4 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-fvFiduDQQxvTter4 .noteText,#mermaid-svg-fvFiduDQQxvTter4 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-fvFiduDQQxvTter4 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fvFiduDQQxvTter4 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fvFiduDQQxvTter4 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fvFiduDQQxvTter4 .actorPopupMenu{position:absolute;}#mermaid-svg-fvFiduDQQxvTter4 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-fvFiduDQQxvTter4 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fvFiduDQQxvTter4 .actor-man circle,#mermaid-svg-fvFiduDQQxvTter4 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-fvFiduDQQxvTter4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客戶端 服務端 seq=x,SYN=1 客戶端發送syn報文, 并置發送序號為x ACK=x+1,seq=y,SYN=1 服務端發送syn+ACK報文 并置發送序號為y, 再確定序號為x+1 ACK=y+1,seq=z 客戶端發送ACK報文, 并置發送序號為z 再確定序號為Y+1 客戶端 服務端
  • 四次揮手
#mermaid-svg-jrVUSX3WCmFRg6w9 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jrVUSX3WCmFRg6w9 .error-icon{fill:#552222;}#mermaid-svg-jrVUSX3WCmFRg6w9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jrVUSX3WCmFRg6w9 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-jrVUSX3WCmFRg6w9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jrVUSX3WCmFRg6w9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jrVUSX3WCmFRg6w9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jrVUSX3WCmFRg6w9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jrVUSX3WCmFRg6w9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jrVUSX3WCmFRg6w9 .marker.cross{stroke:#333333;}#mermaid-svg-jrVUSX3WCmFRg6w9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jrVUSX3WCmFRg6w9 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jrVUSX3WCmFRg6w9 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-jrVUSX3WCmFRg6w9 .actor-line{stroke:grey;}#mermaid-svg-jrVUSX3WCmFRg6w9 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-jrVUSX3WCmFRg6w9 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-jrVUSX3WCmFRg6w9 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-jrVUSX3WCmFRg6w9 .sequenceNumber{fill:white;}#mermaid-svg-jrVUSX3WCmFRg6w9 #sequencenumber{fill:#333;}#mermaid-svg-jrVUSX3WCmFRg6w9 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-jrVUSX3WCmFRg6w9 .messageText{fill:#333;stroke:#333;}#mermaid-svg-jrVUSX3WCmFRg6w9 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jrVUSX3WCmFRg6w9 .labelText,#mermaid-svg-jrVUSX3WCmFRg6w9 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-jrVUSX3WCmFRg6w9 .loopText,#mermaid-svg-jrVUSX3WCmFRg6w9 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-jrVUSX3WCmFRg6w9 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-jrVUSX3WCmFRg6w9 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-jrVUSX3WCmFRg6w9 .noteText,#mermaid-svg-jrVUSX3WCmFRg6w9 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-jrVUSX3WCmFRg6w9 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jrVUSX3WCmFRg6w9 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jrVUSX3WCmFRg6w9 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jrVUSX3WCmFRg6w9 .actorPopupMenu{position:absolute;}#mermaid-svg-jrVUSX3WCmFRg6w9 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-jrVUSX3WCmFRg6w9 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jrVUSX3WCmFRg6w9 .actor-man circle,#mermaid-svg-jrVUSX3WCmFRg6w9 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-jrVUSX3WCmFRg6w9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 主動方 被動方 Fin=1,Ack=z,seq=x 主動方發送Fin+Ack報文, 并置發送序號為X ACK=x+1,seq=z 被動方發送ACK報文, 并置發送序號為Z, 再確定序號為X+1 Fin=1,ack=x,seq=y 被動方發送Fin+Ack報文, 并置發送序號為Y, 再確定序號為X ACK=Y,seq=x 主動方發送ack報文, 并置發送序號為X, 再確認序號為Y 主動方 被動方

2、TCP網絡編程

/*** 客戶端發送信息給服務端,服務端將數據顯示在控制臺上*/ public class TCPTest1 {// 客戶端@Testpublic void client() {Socket socket = null;OutputStream os = null;try {// 1、創建Socket對象,指明服務器端的IP和端口號InetAddress inet = InetAddress.getByName("127.0.0.1");socket = new Socket(inet, 8899);// 2、獲取一個輸出流,用于輸出數據os = socket.getOutputStream();// 3、寫出數據的操作os.write("你好,我是客戶端mm".getBytes());} catch (IOException e) {e.printStackTrace();} finally {// 4、資源的關閉if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}//服務端@Testpublic void server () {ServerSocket ss = null;Socket socket = null;InputStream is = null;ByteArrayOutputStream baos = null;try {// 1、創建服務器端的ServerSocket,指明自己的端口號ss = new ServerSocket(8899);// 2、調用accept()表示接收來自客戶端的socketsocket = ss.accept();// 3、獲取輸入流is = socket.getInputStream();// 4、讀取輸入流中的數據baos = new ByteArrayOutputStream();byte[] buffer = new byte[5];int len;while ((len = is.read(buffer)) != -1) {baos.write(buffer, 0, len);}System.out.println(socket.getInetAddress().getHostAddress() + ":" + baos.toString());} catch (IOException e) {e.printStackTrace();} finally {// 5、關閉資源if (baos != null) {try {baos.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}if (ss != null) {try {ss.close();} catch (IOException e) {e.printStackTrace();}}}} } /*** 客戶端發送文件給服務端,服務端將文件保存在本地*/ public class TCPTest2 {// 客戶端@Testpublic void client () {Socket socket = null;OutputStream os = null;FileInputStream fis = null;try {socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);os = socket.getOutputStream();fis = new FileInputStream(new File("beauty.jpg"));byte[] buffer = new byte[1024];int len;while ((len = fis.read(buffer)) != -1) {os.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}//服務端@Testpublic void server () {ServerSocket ss = null;Socket socket = null;InputStream is = null;FileOutputStream fos = null;try {ss = new ServerSocket(9090);socket = ss.accept();is = socket.getInputStream();fos = new FileOutputStream(new File("beauty1.jpg"));byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}if (ss != null) {try {ss.close();} catch (IOException e) {e.printStackTrace();}}}} } /*** 從客戶端發送文件給服務器,服務端保存到本地。并返回“發送成功”給客戶端* 并關閉相關的連接*/ public class TCPTest3 {// 客戶端@Testpublic void client (){Socket socket = null;OutputStream os = null;FileInputStream fis = null;InputStream is = null;ByteArrayOutputStream baos = null;try {socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);os = socket.getOutputStream();fis = new FileInputStream(new File("beauty.jpg"));byte[] buffer = new byte[1024];int len;while ((len = fis.read(buffer)) != -1) {os.write(buffer, 0, len);}// 關閉數據的輸出socket.shutdownOutput();// 接收來自于服務器端的數據,并顯示到控制臺上is = socket.getInputStream();baos = new ByteArrayOutputStream();byte[] buffer1 = new byte[20];int len1;while ((len1 = is.read(buffer1)) != -1) {baos.write(buffer1, 0, len1);}System.out.println(baos.toString());} catch (IOException e) {e.printStackTrace();} finally {if (baos != null) {try {baos.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}// 服務端@Testpublic void server () {ServerSocket ss = null;Socket socket = null;InputStream is = null;FileOutputStream fos = null;OutputStream os = null;try {ss = new ServerSocket(9090);socket = ss.accept();is = socket.getInputStream();fos = new FileOutputStream(new File("beauty2.jpg"));byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}System.out.println("圖片傳輸完成");// 服務器端給予客戶單反饋os = socket.getOutputStream();os.write("你好,美女,照片我已收到,非常漂亮!".getBytes());} catch (IOException e) {e.printStackTrace();} finally {if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}if (ss != null) {try {ss.close();} catch (IOException e) {e.printStackTrace();}}}} }

3、UDP網絡編程

public class UDPTest {// 發送端@Testpublic void sender () {DatagramSocket socket = null;try {socket = new DatagramSocket();String str = "我是UDP方式發送的導彈";byte[] data = str.getBytes();InetAddress inet = InetAddress.getLocalHost();DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 9090);socket.send(packet);} catch (IOException e) {e.printStackTrace();} finally {if (socket != null) {socket.close();}}}// 接收端@Testpublic void receiver () {DatagramSocket socket = null;try {socket = new DatagramSocket(9090);byte[] buffer = new byte[100];DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);socket.receive(packet);System.out.println(new String(packet.getData(), 0, packet.getLength()));} catch (IOException e) {e.printStackTrace();} finally {socket.close();}} }

4、URL編程

4.1、URL(Uniform Resource Locator)的理解

  • 統一資源定位符,對應著互聯網的某一資源地址

4.2、URL的5個基本結構

  • 協議
  • 主機名
  • 端口號
  • 資源地址
  • 參數列表

4.3、如何實例化

  • URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom")

4.4、常用方法

  • public String getProtocol():獲取該URL的協議名
  • public String getHost():獲取該URL的主機名
  • public String getPort():獲取該URL的端口號
  • public String getPath():獲取該URL的文件路徑
  • public String getFile():獲取該URL的文件名
  • public String getQuery():獲取該URL的查詢名

4.5、可以讀取、下載對應的url資源

public static void main(String[] args) {HttpURLConnection urlConnection = null;InputStream is = null;FileOutputStream fos = null;try {URL url = new URL("http://localhost:8080/examples/beauty.jpg");urlConnection = (HttpURLConnection) url.openConnection();urlConnection.connect();is = urlConnection.getInputStream();fos = new FileOutputStream("day10\\beauty3.jpg");byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}System.out.println("下載完成");} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (urlConnection != null) {urlConnection.disconnect();}} }

八、Java反射機制

1、反射的概述

1.1、本章的主要內容

  • Java反射機制概述
  • 理解Class類并獲取Class實例
  • 類的加載與ClassLoader的理解
  • 創建運行時類的對象
  • 獲取運行時類的完成結構
  • 調用運行時類的指定結構
  • 反射的應用:動態代理

1.2、關于反射的理解

  • Reflection(反射)是被視為動態語言的關鍵,反射機制允許程序在執行期借助于Reflection API取得任何類的內部信息,并能直接操作任意對象的內容屬性及方法。

框架 = 反射 + 注解 + 設計模式

1.3、體會反射機制的“動態性”

/*** 體會反射的動態性*/ @Test public void test2 () {for (int i = 0; i < 100; i++) {int num = new Random().nextInt(3);String classPath = "";switch (num) {case 0:classPath = "java.util.Date";break;case 1:classPath = "java.lang.Object";break;case 2:classPath = "com.atguigu.java.Person";break;}try {Object obj = getInstance(classPath);System.out.println(obj);} catch (Exception e) {e.printStackTrace();}} } /*** 創建一個指定類的對象* @param classPath 指定類的全類名 */ public Object getInstance(String classPath) throws Exception { Class clazz = Class.forName(classPath); return clazz.newInstance(); }

1.4、反射機制能提供的功能

  • 在運行時判斷任意一個對象所屬的類
  • 在運行時構造任意一個類的對象
  • 在運行時判斷任意一個類所具有的成員變量和方法
  • 在運行時獲取泛型信息
  • 在運行時調用任意一個對象的成員變量和方法
  • 在運行時處理注解
  • 生成動態代理

1.5、相關API

  • java.lang.Class:反射的源頭
  • java.lang.reflect.Method
  • java.lang.reflect.Field
  • java.lang.reflect.Constructor

2、Class類的理解與獲取Class的實例

2.1、Class類的理解

  • 類的加載過程
    • 程序經過javac.exe命令以后,會生成一個或多個字節碼文件(.class結尾)。接著我們使用java.exe命令對某個字節碼文件進行解釋運行。相當于將某個字節碼文件加載到內存中。此過程就稱為類的加載。加載到內存中的類,我們就稱為運行時類,此運行時類,就作為Class的一個實例。
  • 換句話說,Class的實例就對應著一個運行時類
  • 加載到內存中的運行時類,會緩存一定的時間。在此時間之內,我們可以通過不同的方式來獲取此運行時類。

2.2、獲取Class實例的幾種方式

@Test public void test3() throws ClassNotFoundException {// 方式一:調用運行時類的屬性:.classClass clazz1 = Person.class;System.out.println(clazz1);// 方式二:通過運行時類的對象,調用getClass()Person p1 = new Person();Class clazz2 = p1.getClass();System.out.println(clazz2);// 方式三:調用Class的靜態方法:forName(String classPath)Class clazz3 = Class.forName("com.atguigu.java.Person");System.out.println(clazz3);// 方式四:使用類的加載器:ClassLoader(了解)ClassLoader classLoader = ReflectionTest.class.getClassLoader();Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");System.out.println(clazz4);System.out.println(clazz1 == clazz2);// trueSystem.out.println(clazz1 == clazz3);// trueSystem.out.println(clazz1 == clazz4);// true }

2.3、總結:創建類的對象的方式

  • 方式一:new + 構造器
  • 方式二:要創建Xxx類的對象,可以考慮:Xxx、Xxxs、XxxFactory、XxxBuilder類中查看是否有靜態方法的存在??梢哉{用其靜態方法,創建Xxx對象
  • 方式三:通過反射

2.4、Class實例可以是哪些結構的說明

  • class:外部類,成員(成員內部類,靜態內部類),局部內部類,匿名內部類
  • interface:接口
  • []:數組
  • enum:枚舉
  • annotation:注解@interface
  • primitive type:基本數據類型
  • void

3、了解ClassLoader

3.1、類的加載過程(了解)

  • 當程序主動使用某個類時,如果該類還未被加載到內存中,則系統會通過如下三個步驟來對該類進行初始化。
    • 類的加載:將類的class文件讀入內存,并為之創建一個java.lang.Class對象。此過程由類加載器完成
    • 類的鏈接:將類的二進制數據合并到JRE中
    • 類的初始化:JVM負責對類進行初始化

3.2、類的加載器的作用

  • 類加載的作用:將class文件字節碼內容加載到內存中,并將這些靜態數據轉換成方法區的運行時數據結構,然后在堆中生成一個代表這個類的java.lang.Class對象,作為方法區中類數據的訪問入口。
  • 類緩存:標準的JavaSE類加載器可以按要求查找類,但一旦某個類被加載到類加載器中,它將維持加載(緩存)一段時間。不過JVM垃圾回收機制可以回收這些Class對象。

3.3、類的加載器的分類

  • 引導類加載器:用C++編寫的,是JVM自帶的類加載器,負責Java平臺核心庫,用來裝載核心類庫。該加載器無法直接獲取
  • 擴展類加載器:負責jre/lib/ext目錄下的jar包或-D java.ext.dirs指定目錄下的jar包裝入工作庫
  • 系統類加載器:負責java -classpath 或 -D java.class.path所指的目錄下的類與jar包裝入工作,是最常用的加載器

3.4、Java類編譯、運行的執行過程

#mermaid-svg-AM35lXhDlGQXMOXi {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-AM35lXhDlGQXMOXi .error-icon{fill:#552222;}#mermaid-svg-AM35lXhDlGQXMOXi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AM35lXhDlGQXMOXi .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-AM35lXhDlGQXMOXi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AM35lXhDlGQXMOXi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AM35lXhDlGQXMOXi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AM35lXhDlGQXMOXi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AM35lXhDlGQXMOXi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AM35lXhDlGQXMOXi .marker.cross{stroke:#333333;}#mermaid-svg-AM35lXhDlGQXMOXi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AM35lXhDlGQXMOXi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AM35lXhDlGQXMOXi .cluster-label text{fill:#333;}#mermaid-svg-AM35lXhDlGQXMOXi .cluster-label span{color:#333;}#mermaid-svg-AM35lXhDlGQXMOXi .label text,#mermaid-svg-AM35lXhDlGQXMOXi span{fill:#333;color:#333;}#mermaid-svg-AM35lXhDlGQXMOXi .node rect,#mermaid-svg-AM35lXhDlGQXMOXi .node circle,#mermaid-svg-AM35lXhDlGQXMOXi .node ellipse,#mermaid-svg-AM35lXhDlGQXMOXi .node polygon,#mermaid-svg-AM35lXhDlGQXMOXi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AM35lXhDlGQXMOXi .node .label{text-align:center;}#mermaid-svg-AM35lXhDlGQXMOXi .node.clickable{cursor:pointer;}#mermaid-svg-AM35lXhDlGQXMOXi .arrowheadPath{fill:#333333;}#mermaid-svg-AM35lXhDlGQXMOXi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AM35lXhDlGQXMOXi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AM35lXhDlGQXMOXi .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-AM35lXhDlGQXMOXi .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-AM35lXhDlGQXMOXi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AM35lXhDlGQXMOXi .cluster text{fill:#333;}#mermaid-svg-AM35lXhDlGQXMOXi .cluster span{color:#333;}#mermaid-svg-AM35lXhDlGQXMOXi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AM35lXhDlGQXMOXi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 源程序 Java編譯器 字節碼 類裝載器 字節碼校驗器 解釋器 操作系統平臺

3.5、使用Classloader加載src目錄下的配置文件

@Test public void test2() throws Exception {Properties pros = new Properties();// 讀取配置文件的方式一:// FileInputStream fis = new FileInputStream("src\\jdbc1.properties");// pros.load(fis);// 讀取配置文件的方式二:ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();InputStream is = classLoader.getResourceAsStream("jdbc1.properties");pros.load(is);String user = pros.getProperty("user");String password = pros.getProperty("password");System.out.println("user = " + user + ",password = " + password); }

4、反射應用一:創建運行時類的對象

  • newInstance():調用此方法,創建對應的運行時類的對象。內部調用了運行時類的空參的構造器
  • 要想此方法正常的創建運行時類的對象,要求:
    • 1、運行時類必須提供空參的構造器
    • 2、空參的構造器的訪問權限得夠。通常,設置為public
  • 在JavaBean中要求提供一個public的空參構造器。原因:
    • 1、便于通過反射,創建運行時類的對象
    • 2、便于子類繼承此運行時類時,默認調用super()時,保證父類有此構造器
@Test public void test1() throws InstantiationException, IllegalAccessException {Class<Person> clazz = Person.class;Person person = clazz.newInstance();System.out.println(person); }

5、反射應用二:獲取運行時類的完整結構

5.1、獲取屬性

@Test public void test1() {Class clazz = Person.class;// 獲取屬性結構// getFields():獲取當前運行時類及其父類中聲明為public訪問權限的屬性Field[] fields = clazz.getFields();for (Field f : fields) {System.out.println(f);}System.out.println();// getDeclaredFields():獲取當前運行時類中聲明的所有屬性。(不包含父類中聲明的屬性)Field[] declaredFields = clazz.getDeclaredFields();for (Field f : declaredFields) {System.out.println(f);} }

5.2、獲取方法

@Test public void test1 () {Class clazz = Person.class;// getMethods():獲取當前運行時類及其所有父類中聲明為public權限的方法Method[] methods = clazz.getMethods();for (Method m : methods) {System.out.println(m);}System.out.println();// getDeclaredMethods():獲取當前運行時類中聲明的所有方法。(不包含父類中聲明的方法)Method[] declaredMethods = clazz.getDeclaredMethods();for (Method m : declaredMethods) {System.out.println(m);} }

5.3、獲取其他結構

/*** 獲取構造器結構*/ @Test public void test1 () {Class clazz = Person.class;// getConstructors():獲取當前運行時類中聲明為public的構造器Constructor[] constructors = clazz.getConstructors();for (Constructor c : constructors) {System.out.println(c);}System.out.println();// getDeclaredConstructors():獲取當前運行時類中聲明的所有構造器Constructor[] declaredConstructors = clazz.getDeclaredConstructors();for (Constructor c : declaredConstructors) {System.out.println(c);} } /*** 獲取運行時類的父類*/ @Test public void test2 () {Class clazz = Person.class;Class superclass = clazz.getSuperclass();System.out.println(superclass); } /*** 獲取運行時類的帶泛型的父類*/ @Test public void test3 () {Class clazz = Person.class;Type genericSuperclass = clazz.getGenericSuperclass();System.out.println(genericSuperclass); } /*** 獲取運行時類的帶泛型的父類的泛型*/ @Test public void test4 () {Class clazz = Person.class;Type genericSuperclass = clazz.getGenericSuperclass();ParameterizedType paramType = (ParameterizedType) genericSuperclass;// 獲取泛型類型Type[] actualTypeArguments = paramType.getActualTypeArguments();for (Type type : actualTypeArguments) {System.out.println(type.getTypeName());} } /*** 獲取運行時類實現的接口*/ @Test public void test5 () {Class clazz = Person.class;Class[] interfaces = clazz.getInterfaces();for (Class c : interfaces) {System.out.println(c);}System.out.println();//獲取運行時類的父類實現的接口Class[] interfaces1 = clazz.getSuperclass().getInterfaces();for (Class c : interfaces1) {System.out.println(c);} } /*** 獲取運行時類所在的包*/ @Test public void test6 () {Class clazz = Person.class;Package pack = clazz.getPackage();System.out.println(pack); } /*** 獲取運行時類聲明的注解*/ public void test7 () {Class clazz = Person.class;Annotation[] annotations = clazz.getAnnotations();for (Annotation annos : annotations) {System.out.println(annos);} }

6、反射應用三:調用運行時類的指定結構

6.1、調用指定的屬性

@Testpublic void testField1 () throws Exception {Class clazz = Person.class;// 創建運行時類的對象Person p = (Person) clazz.newInstance();// 1、getDeclaredField(String fieldName):獲取運行時類中指定變量名的屬性Field name = clazz.getDeclaredField("name");// 2、保證當前屬性時可訪問的name.setAccessible(true);// 3、獲取、設置指定對象的此屬性值name.set(p, "Tom");System.out.println(name.get(p));}

6.2、調用指定的方法

@Test public void testMethod () throws Exception {Class clazz = Person.class;// 創建運行時類的對象Person p = (Person) clazz.newInstance();// 1、獲取指定的某個方法// getDeclaredMethod():參數1指明獲取的方法的名稱 參數2指明獲取的方法的形參類型Method show = clazz.getDeclaredMethod("show", String.class);// 2、保證當前方法是可訪問的show.setAccessible(true);// 3、調用方法的invoke():參數1方法的調用者 參數2給方法形參賦值的實參// invoke()的返回值即為對應類中調用的方法的返回值Object returnValue = show.invoke(p, "CHN");System.out.println(returnValue);// 如何調用靜態方法Method showDesc = clazz.getDeclaredMethod("showDesc");showDesc.setAccessible(true);// 如果調用的運行時類中的方法沒有返回值,則此invoke()返回null// Object returnVal = showDesc.invoke(null);Object returnVal = showDesc.invoke(Person.class);System.out.println(returnVal); }

6.3、調用指定的構造器

@Test public void testConstructor() throws Exception {Class clazz = Person.class;// 1、獲取指定的構造器// getDeclaredConstructor():參數指明構造器的參數列表Constructor constructor = clazz.getDeclaredConstructor(String.class);// 2、保證此構造器是可訪問的constructor.setAccessible(true);// 3、調用此構造器創建運行時類的對象Person per = (Person) constructor.newInstance("Tom");System.out.println(per); }

7、反射應用四:動態代理

7.1、代理模式的原理

  • 使用一個代理將對象包裝起來,然后用該代理對象取代原始對象。任何對原始對象的調用都要通過代理。代理對象決定是否以及何時將方法調用轉到原始對象上。

7.2、靜態代理

// 被代理類 Class MyThread implements Runnable () {} // 代理類 Class Thread implements Runnable() {} // 代理操作 main () {MyThread t = new MyThread();Thread thread = new Thread(t);thread.start();// 啟動線程;調用線程的run() }
  • 靜態代理的缺點
    • 代理類和目標對象的類都是在編譯期間確定下來,不利于程序的擴展。
    • 每一個代理類只能為一個接口服務,這樣一來程序開發中必然產生過多的代理。

7.3、動態代理的特點

  • 動態代理是指客戶通過代理類來調用其它對象的方法,并且是在程序運行時根據需要動態創建目標類的代理對象。

7.4、動態代理的實現

  • 需要解決的兩個主要問題:
    • 問題一:如何根據加載到內存中的被代理類,動態創建一個代理類及其對象 --> 通過Proxy.newProxyInstance()實現
    • 問題二:當通過代理類的對象調用方法a時,如何動態的去調用被代理類中的同名方法a --> 通過InvocationHandler接口的實現類及其方法invoke()
/*** 動態代理體會:反射的動態性*/ interface Human {String getBelief();void eat(String food); } // 被代理類 class SuperMan implements Human {@Overridepublic String getBelief() {return "I believe I can fly!";}@Overridepublic void eat(String food) {System.out.println("我喜歡吃" + food);} } class HumanUtil {public void method1 () {System.out.println("=======通用方法一=======");}public void method2 () {System.out.println("=======通用方法二=======");} } class ProxyFactory {// 調用此方法,返回一個代理類的對象。解決問題一public static Object getProxyInstance(Object obj) {// obj:被代理類的對象MyInvocationHandler handler = new MyInvocationHandler();handler.bind(obj);return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);} } class MyInvocationHandler implements InvocationHandler {private Object obj;// 需要使用被代理類的對象進行賦值public void bind(Object obj) {this.obj = obj;}// 當我們通過代理類的對象,調用方法a時,就會自動的調用如下的方法:invoke()@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {HumanUtil util = new HumanUtil();util.method1();// method:即為代理類對象調用的方法,此方法也就作為了被代理類對象要調用的方法// obj:被代理類的對象Object returnValue = method.invoke(obj, args);util.method2();// 上述方法的返回值就作為當前類中的invoke()返回值return returnValue;} } public class ProxyTest {public static void main(String[] args) {SuperMan superMan = new SuperMan();// proxyInstance:代理類的對象Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);// 當通過代理類對象調用方法時,會自動的調用被代理類中同名的方法String belief = proxyInstance.getBelief();System.out.println(belief);proxyInstance.eat("四川麻辣燙");} }

九、Java8的其它新特性

1、Java8的新特性概述

  • 函數式接口
  • Lambda表達式
  • 方法引用/構造器引用
  • Stream API
    • 并行流
    • 串行流
  • 接口的增強
    • 靜態方法
    • 默認方法
  • Optional類
  • 新的時間和日期API
  • 其它新特性
    • 重復注解
    • 類型注解
    • 通用目標類型推斷
    • JDK的更新
      • 集合的流式操作
      • 并發
      • Arrays
      • Number和Math
      • IO/NIO的改進
      • Reflection獲取形參名
      • String:join()
      • Files
    • 新編譯工具:jjs、jdeps
    • JVM中Metaspace取代PermGen空間

2、Lambda表達式

2.1、Lambda表達式使用前后的對比

@Test public void test1 () {Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("我愛北京天安門");}};r1.run();// 使用lambda表達式Runnable r2 = () -> System.out.println("我愛北京天安門");r2.run(); } @Test public void test2 () {Comparator<Integer> com1 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return Integer.compare(o1, o2);}};System.out.println(com1.compare(12, 21));// Lambda表達式的寫法Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);System.out.println(com2.compare(32, 21));// 方法引用Comparator<Integer> com3 = Integer :: compare;System.out.println(com3.compare(32, 21)); }

2.2、Lambda表達式的基本語法

  • 舉例:(o1, o2) -> Integer.compare(o1, o2);
  • 格式:
    • ->:lambda操作符或箭頭操作符
    • ->左邊:lambda形參列表(其實就是接口中的抽象方法的形參列表)
    • ->右邊:lambda體(其實就是重寫的抽象方法的方法體)

2.3、如何使用:分為六種情況

  • 語法格式一:無參,無返回值
    • Runnable r1 = () -> {System.out.println("Hello Lambda!");};
  • 語法格式二:Lambda需要一個參數,但是沒有返回值
    • Consumer<String> con = (String str) -> {System.out.println(str);};
  • 語法格式三:數據類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”
    • Consumer<String> con = (str) -> {System.out.println(str);};
  • 語法格式四:Lambda若只需要一個參數時,參數的小括號可以省略
    • Consumer<String> con = str -> {System.out.println(str);};
  • 語法格式五:Lambda需要兩個或以上的參數,多條執行語句,并且可以有返回值
    • Comparator<Integer> com = (x, y) -> {System.out.println("實現函數式接口方法!"); return Integer.compare(x, y);};
  • 語法格式六:當Lambda體只有一條語句時,return與大括號若有,都可以省略
    • Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

總結六種情況:
->左邊:lambda形參列表的參數類型可以省略(類型推斷);如果lambda形參列表只有一個參數,其一對()也可以省略
->右邊:lambda體應該使用一對{}包裹;如果lambda體只有一條執行語句(可能是return語句,省略這一對{}和return關鍵字)

3、函數式接口

3.1、函數式接口的使用說明

  • 如果一個接口中,只聲明了一個抽象方法,則此接口就稱為函數式接口
  • 我們可以在一個接口上使用@FunctionalInterface注解,這樣做可以檢查它是否是一個函數式接口
  • Lambda表達式的本質:作為函數式接口的實例

3.2、Java8中關于Lambda表達式提供的4個基本的函數式接口

函數式接口參數類型返回類型用途
Consumer<T>消費型接口Tvoid對類型為T的對象應用操作,包含方法:void accept(T t)
Supplier<T>供給型接口T返回類型為T的對象,包含方法:T get()
Function<T, R>函數型接口TR對類型為T的對象應用操作,并返回結果。結果是R類型的對象。包含方法:R apply(T t)
Predicate<T>斷定型接口Tboolean確定類型為T的對象是否滿足某約束,并返回boolean值。包含方法:boolean test(T t)

3.3、總結

  • 何時使用lambda表達式?
    • 當需要對一個函數式接口實例化的時候,可以使用lambda表達式
  • 何時使用給定的函數式接口?
    • 如果我們開發中需要定義一個函數式接口,首先看看在已有的JDK提供的函數式接口是否提供了能滿足需求的函數式接口。如果有,則直接調用即可,不需要自己再自定義了。

4、方法引用

4.1、理解

  • 方法引用可以看做是Lambda表達式深層次的表達。換句話說,方法引用就是Lambda表達式,也就是函數式接口的一個實例,通過方法的名字來指向一個方法。

4.2、使用情境

  • 當要傳遞給Lambda體的操作,已經有實現的方法了,可以使用方法引用

4.3、格式

  • 類(或對象) :: 方法名

4.4、分為如下的三種情況

  • 對象 :: 非靜態方法 --> 情況1
  • 類 :: 靜態方法 --> 情況2
  • 類 :: 非靜態方法 --> 情況3

4.5、要求

  • 要求接口中的抽象方法的形參列表和返回值類型與方法引用的方法的形參列表和返回值類型相同!(針對于情況1和情況2)
  • 當函數式接口方法的第一個參數是需要引用方法的調用者,并且第二個參數是需要引用方法的參數(或無參數)時:ClassName :: methodName(針對于情況3)

4.6、使用建議

  • 如果給函數式接口提供實例,恰好滿足方法引用的使用情境,大家就可以考慮使用方法引用給函數式接口提供實例。如果大家不熟悉方法引用,那么還可以使用lambda表達式。

4.7、使用舉例

// 情況一:對象 :: 實例方法 // Consumer中的void accept(T t) // PrintStream中的void println(T t) @Test public void test1 () {Consumer<String> con1 = str -> System.out.println(str);con1.accept("北京");// 方法引用PrintStream ps = System.out;Consumer<String> con2 = ps::println;con2.accept("beijing"); } // 情況二:類 :: 靜態方法 // Comparator中int compare(T t1, T t2) // Integer中的int compare(T t1, T t2) @Test public void test3 () {Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2);System.out.println(com1.compare(12,21));// 方法引用Comparator<Integer> com2 = Integer::compare;System.out.println(com2.compare(12, 3)); } // 情況三:類 :: 實例方法 // Comparator中的int compare(T t1, T t2) // String中的int t1.compareTo(t2) @Test public void test5 () {Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);System.out.println(com1.compare("abc", "abd"));// 方法引用Comparator<String> com2 = String :: compareTo;System.out.println(com2.compare("adb", "abm")); }

5、構造器引用與數組引用

5.1、構造器引用格式

  • 類名::new

5.2、構造器引用使用要求

  • 和方法引用類似,函數式接口的抽象方法的形參列表和構造器的形參列表一致。抽象方法的返回值類型即為構造器所屬的類的類型

5.3、構造器引用舉例

// 構造器引用 // Supplier的T get() // Employee的空參構造器:Employee() @Test public void test1 () {Supplier<Employee> sup = new Supplier<Employee>() {@Overridepublic Employee get() {return new Employee();}};// lambda表達式Supplier<Employee> sup1 = () -> new Employee();System.out.println(sup1.get());// 構造器引用Supplier<Employee> sup2 = Employee :: new;System.out.println(sup2.get()); } // Function中的R apply(T t) @Test public void test2 () {Function<Integer, Employee> func1 = id -> new Employee(id);System.out.println(func1.apply(1001));// 構造器引用Function<Integer, Employee> func2 = Employee :: new;System.out.println(func2.apply(1002)); }

5.4、數組引用格式

  • 數組類型[]::new

5.5、數組引用舉例

// 數組引用 // Function中的R apply(T t) @Test public void test4 () {Function<Integer, String[]> func1 = length -> new String[length];System.out.println(Arrays.toString(func1.apply(5)));// 數組引用Function<Integer, String[]> func2 = String[] :: new;System.out.println(Arrays.toString(func2.apply(10))); }

6、Stream API

6.1、Stream API的理解

  • Stream關注的是對數據的運算,與CPU打交道;集合關注的是數據的存儲,與內存打交道
  • Java 8提供了一套API,使用這套API可以對內存中的數據進行過濾、排序、映射、歸約等操作。類似SQL對數據庫中表的相關操作。

6.2、注意點

  • Stream自己不會存儲元素
  • Stream不會改變源對象。相反,他們會返回一個持有結果的新的Stream
  • Stream操作是延遲執行的。這意味著他們會等到需要結果的時候才執行

6.3、Stream的使用流程

  • Stream的實例化
  • 一系列的中間操作(過濾、映射、…)
  • 終止操作

6.4、使用流程的注意點

  • 一個中間操作鏈,對數據源的數據進行處理
  • 一旦執行終止操作,就執行中間操作鏈,并產生結果。之后,不會再被使用。

6.5、步驟一:Stream實例化

// 創建Stream方式一:通過集合 @Test public void test1 () {List<Employee> employees = EmployeeData.getEmployees();// default Stream<E> stream():返回一個順序流Stream<Employee> stream = employees.stream();// default Stream<E> parallelStream():返回一個并行流Stream<Employee> parallelStream = employees.parallelStream(); } // 創建Stream方式二:通過數組 @Test public void test2 () {int[] arr = new int[]{1,2,3,4,5,6};// 調用Arrays類的static <T> Stream<T> stream(T[] array):返回一個流IntStream stream = Arrays.stream(arr); } // 創建Stream方式三:通過Stream的of() @Test public void test3 () {Stream<Integer> stream = Stream.of(1,2,3,4,5,6); } // 創建Stream方式四:創建無限流 @Test public void test4 () {// 迭代// public static <T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)// 遍歷前10個偶數Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);// 生成// public static <T> Stream<T> generate(Supplier<T> s)Stream.generate(Math::random).limit(10).forEach(System.out::println); }

6.6、步驟二:中間操作

  • 篩選與切片
    • filter(Predicate p):接收Lambda,從流中排除某些元素
    • distinct():篩選,通過流所生成元素的hashCode()和equals()去除重復元素
    • limit(long maxSize):截斷流,使其元素不超過給定數量
    • skip(long n):跳過元素,返回一個扔掉了前n個元素的流。若流中元素不足n個,則返回一個空流。與limit(n)互補
  • 映射
    • map(Function f):接收一個函數作為參數,該函數會被應用到每個元素上,并將其映射成一個新的元素
    • mapToDouble(ToDoubleFunction f):接收一個函數作為參數,該函數會被應用到每個元素上,產生一個新的DoubleStream
    • mapToInt(ToIntFunction f):接收一個函數作為參數,該函數會被應用到每個元素上,產生一個新的IntStream
    • mapToLong(ToLongFunction f):接收一個函數作為參數,該函數會被應用到每個元素上,產生一個新的LongStream
    • flatMap(Function f):接收一個函數作為參數,將流中的每個值都換成另一個流,然后把所有流連接成一個流
  • 排序
    • sorted():產生一個新流,其中按自然順序排序
    • sorted(Comparator com):產生一個新流,其中按比較器順序排序

6.7、步驟三:終止操作

  • 匹配與查找
    • allMatch(Predicate p):檢查是否匹配所有元素
    • anyMatch(Predicate p):檢查是否至少匹配一個元素
    • noneMatch(Predicate p):檢查是否沒有匹配所有元素
    • findFirst():返回第一個元素
    • findAny():返回當前流中的任意元素
    • count():返回流中元素總數
    • max(Comparator c):返回流中最大值
    • min(Comparator c):返回流中最小值
    • forEach(Consumer c):內部迭代(使用Collection接口需要用戶去做迭代,稱為外部迭代。相反,Stream API使用內部迭代——它幫你把迭代做了)
  • 歸約
    • reduce(T iden, BinaryOperator b):可以將流中元素反復結合起來,得到一個值。返回T
    • reduce(BinaryOperator b):可以將流中元素反復結合起來,得到一個值。返回Optional<T>
  • 收集
    • collect(Collector c):將流轉換為其他形式。接收一個Collector接口的實現,用于給Stream中元素做匯總的方法(Collector通過Collectors提供實例)
      • toList()
      • toSet()
      • toCollection()

7、Optional類的使用

7.1、理解

  • 為了解決Java中的空指針問題而生!
  • Optional<T>類(java.util.Optional)是一個容器類,它可以保存類型T的值,代表這個值存在。或者僅僅保存null,表示這個值不存在。原來用null表示一個值不存在,現在Optional可以更好的表達這個概念。并且可以避免空指針異常。

7.2、常用方法

@Test public void test1 () {// empty():創建的Optional對象內部的value = nullOptional<Object> op1 = Optional.empty();if (!op1.isPresent()) {// Optional封裝的數據是否包含數據System.out.println("數據為空");}// 如果Optional封裝的數據value為空,則get()報錯。否則,value不為空時,返回value// System.out.println(op1.get()); } @Test public void test2 () {String str = "hello";// of(T t):封裝數據t生成Optional對象,要求t非空,否則報錯Optional<String> op1 = Optional.of(str);// get()通常與of()方法搭配使用。用于獲取內部的封裝的數據valueString str1 = op1.get();System.out.println(str1); } @Test public void test3 () {String str = "beijing";str = null;// ofNullable(T t):封裝數據t賦給Optional內部的value。不要求t非空Optional<String> op1 = Optional.ofNullable(str);// orElse(T t1):如果Optional內部的value非空,則返回此value值。如果value為空,則返回t1String str2 = op1.orElse("shanghai");System.out.println(str2); }

總結

以上是生活随笔為你收集整理的尚硅谷Java入门视频教程(在线答疑+Java面试真题)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

人人妻人人澡人人爽欧美一区 | 久青草影院在线观看国产 | 亚洲精品一区二区三区大桥未久 | 亚洲精品成人av在线 | 亚洲国产精品毛片av不卡在线 | 国产高潮视频在线观看 | 真人与拘做受免费视频 | 色婷婷综合中文久久一本 | 午夜丰满少妇性开放视频 | 青青久在线视频免费观看 | 亚洲精品美女久久久久久久 | 精品亚洲成av人在线观看 | 国内精品人妻无码久久久影院蜜桃 | 精品偷拍一区二区三区在线看 | 亚洲色偷偷偷综合网 | 伊人久久婷婷五月综合97色 | 一本精品99久久精品77 | 亚洲精品欧美二区三区中文字幕 | 国产高清av在线播放 | 无码人妻丰满熟妇区毛片18 | 欧美日韩人成综合在线播放 | 亚洲人成网站免费播放 | 国内精品久久毛片一区二区 | 亚洲成av人片天堂网无码】 | 亚洲伊人久久精品影院 | 99久久久无码国产精品免费 | 大肉大捧一进一出好爽视频 | 捆绑白丝粉色jk震动捧喷白浆 | 天天摸天天透天天添 | 免费乱码人妻系列无码专区 | 一区二区传媒有限公司 | 亚洲精品成人福利网站 | 久久99精品国产.久久久久 | 国产日产欧产精品精品app | 最新国产乱人伦偷精品免费网站 | 国产又爽又猛又粗的视频a片 | 蜜桃臀无码内射一区二区三区 | 人人妻人人藻人人爽欧美一区 | 久9re热视频这里只有精品 | √8天堂资源地址中文在线 | 77777熟女视频在线观看 а天堂中文在线官网 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 亚洲精品一区二区三区在线 | 熟女俱乐部五十路六十路av | 日韩欧美中文字幕公布 | 欧美35页视频在线观看 | 国产在线aaa片一区二区99 | 乱码午夜-极国产极内射 | 青青草原综合久久大伊人精品 | 永久免费观看国产裸体美女 | 午夜成人1000部免费视频 | 国产suv精品一区二区五 | 在线а√天堂中文官网 | 久9re热视频这里只有精品 | 国产无遮挡吃胸膜奶免费看 | 久久婷婷五月综合色国产香蕉 | 亚洲国产精品无码久久久久高潮 | 青青久在线视频免费观看 | 麻豆人妻少妇精品无码专区 | 亚洲色无码一区二区三区 | 欧美精品免费观看二区 | 女人被男人爽到呻吟的视频 | 国产亚洲精品久久久ai换 | 亚洲а∨天堂久久精品2021 | 国产在热线精品视频 | 国产亚洲欧美在线专区 | 国产精品多人p群无码 | 日日天日日夜日日摸 | 性色av无码免费一区二区三区 | 一本加勒比波多野结衣 | 99精品无人区乱码1区2区3区 | 国产亚洲精品久久久久久久 | 免费网站看v片在线18禁无码 | 鲁一鲁av2019在线 | 亚洲精品久久久久中文第一幕 | 免费网站看v片在线18禁无码 | 白嫩日本少妇做爰 | 四虎影视成人永久免费观看视频 | 免费观看的无遮挡av | 国产亚洲欧美在线专区 | 中文无码成人免费视频在线观看 | 中文字幕乱码人妻无码久久 | 狠狠噜狠狠狠狠丁香五月 | 国产小呦泬泬99精品 | 亚洲 欧美 激情 小说 另类 | 亚洲毛片av日韩av无码 | 久久久国产精品无码免费专区 | 久久精品国产99精品亚洲 | 国产疯狂伦交大片 | 亚洲码国产精品高潮在线 | 任你躁国产自任一区二区三区 | 精品无码国产一区二区三区av | 一本色道久久综合狠狠躁 | 无码福利日韩神码福利片 | 国产超级va在线观看视频 | av无码不卡在线观看免费 | 国产情侣作爱视频免费观看 | 黑人巨大精品欧美一区二区 | 色综合久久中文娱乐网 | 久久久久久九九精品久 | 国产精品久久久久久亚洲毛片 | 无码人妻出轨黑人中文字幕 | 国产亚洲精品久久久久久国模美 | 日韩精品一区二区av在线 | 性色欲网站人妻丰满中文久久不卡 | 无码av中文字幕免费放 | 高清无码午夜福利视频 | 国产精品人人妻人人爽 | 日日碰狠狠丁香久燥 | 国内揄拍国内精品人妻 | 日韩少妇白浆无码系列 | 亚洲精品国偷拍自产在线观看蜜桃 | 蜜桃无码一区二区三区 | 亚洲国产成人a精品不卡在线 | 亚洲国产精品久久人人爱 | 成熟女人特级毛片www免费 | 亚洲国产精品毛片av不卡在线 | 国产两女互慰高潮视频在线观看 | 国产亚洲人成a在线v网站 | 性欧美熟妇videofreesex | 无码人妻久久一区二区三区不卡 | 狠狠色丁香久久婷婷综合五月 | 国产偷自视频区视频 | 国产人妻精品午夜福利免费 | 国产情侣作爱视频免费观看 | 久久亚洲中文字幕无码 | 欧美 日韩 人妻 高清 中文 | 97精品国产97久久久久久免费 | 精品人人妻人人澡人人爽人人 | 精品国偷自产在线视频 | 性欧美videos高清精品 | 中文字幕乱妇无码av在线 | 六月丁香婷婷色狠狠久久 | 久久精品人人做人人综合 | 中文字幕av日韩精品一区二区 | 天下第一社区视频www日本 | 亚洲精品鲁一鲁一区二区三区 | 久久综合狠狠综合久久综合88 | a片在线免费观看 | 国产成人无码一二三区视频 | 狠狠色欧美亚洲狠狠色www | 午夜福利试看120秒体验区 | 图片区 小说区 区 亚洲五月 | 国产亚洲精品精品国产亚洲综合 | 国产成人精品三级麻豆 | 亚洲精品无码国产 | 国产乱人偷精品人妻a片 | 国产成人精品优优av | 在线观看欧美一区二区三区 | 国产亚av手机在线观看 | 亚洲色无码一区二区三区 | 精品国产福利一区二区 | 荫蒂添的好舒服视频囗交 | 亚洲乱码中文字幕在线 | 国产乱人偷精品人妻a片 | 国产精品.xx视频.xxtv | 亚洲综合无码久久精品综合 | 午夜无码区在线观看 | 熟妇人妻中文av无码 | 成人无码视频在线观看网站 | a片在线免费观看 | 亚洲阿v天堂在线 | 久久综合给久久狠狠97色 | 国产成人综合色在线观看网站 | www国产亚洲精品久久久日本 | 特黄特色大片免费播放器图片 | 日本一本二本三区免费 | 日韩无套无码精品 | 国产艳妇av在线观看果冻传媒 | 日产精品99久久久久久 | 1000部夫妻午夜免费 | 最近免费中文字幕中文高清百度 | 精品人妻av区 | 天堂а√在线中文在线 | 精品一区二区三区无码免费视频 | 国产精品美女久久久网av | 久久久久久九九精品久 | 人人妻人人澡人人爽欧美一区 | 蜜臀av在线播放 久久综合激激的五月天 | 成熟妇人a片免费看网站 | 日韩精品a片一区二区三区妖精 | 国产办公室秘书无码精品99 | 丝袜足控一区二区三区 | 日韩精品无码免费一区二区三区 | 色综合久久中文娱乐网 | 中文字幕日韩精品一区二区三区 | 亚洲精品午夜国产va久久成人 | 思思久久99热只有频精品66 | 亚洲国产精品一区二区美利坚 | 伊人色综合久久天天小片 | 狠狠色噜噜狠狠狠7777奇米 | 青青青手机频在线观看 | 蜜桃臀无码内射一区二区三区 | 久久精品国产一区二区三区肥胖 | 2019nv天堂香蕉在线观看 | 国内精品人妻无码久久久影院蜜桃 | 国产肉丝袜在线观看 | 欧美国产日韩久久mv | 色噜噜亚洲男人的天堂 | 久久熟妇人妻午夜寂寞影院 | 在线播放免费人成毛片乱码 | 国产精品人人妻人人爽 | 性做久久久久久久久 | 欧美自拍另类欧美综合图片区 | 日韩av无码中文无码电影 | 亚洲 高清 成人 动漫 | 亚洲а∨天堂久久精品2021 | 丰满少妇人妻久久久久久 | 亚洲人成影院在线无码按摩店 | 十八禁视频网站在线观看 | 亚洲精品一区二区三区在线 | 亚洲熟熟妇xxxx | 婷婷丁香六月激情综合啪 | 久久综合给久久狠狠97色 | 国产色xx群视频射精 | 99国产欧美久久久精品 | 99久久精品午夜一区二区 | 1000部啪啪未满十八勿入下载 | 欧洲美熟女乱又伦 | 日日噜噜噜噜夜夜爽亚洲精品 | 丝袜美腿亚洲一区二区 | 精品国产一区二区三区四区 | 男女猛烈xx00免费视频试看 | 欧美兽交xxxx×视频 | 任你躁在线精品免费 | 丰满少妇弄高潮了www | 无码精品国产va在线观看dvd | 美女黄网站人色视频免费国产 | 亚洲国产精品美女久久久久 | 亚洲成av人综合在线观看 | 超碰97人人做人人爱少妇 | 天天燥日日燥 | 午夜丰满少妇性开放视频 | 一本无码人妻在中文字幕免费 | 久久久久久久久888 | 久久综合九色综合欧美狠狠 | 久久久久99精品成人片 | 清纯唯美经典一区二区 | 久久久久久久人妻无码中文字幕爆 | 国产精品无码一区二区三区不卡 | 麻豆国产97在线 | 欧洲 | 亚洲色成人中文字幕网站 | 欧美兽交xxxx×视频 | 十八禁视频网站在线观看 | 久久国产精品精品国产色婷婷 | 国产亚洲欧美日韩亚洲中文色 | 成年女人永久免费看片 | 国产成人久久精品流白浆 | 天干天干啦夜天干天2017 | 欧美第一黄网免费网站 | 老子影院午夜精品无码 | 99久久婷婷国产综合精品青草免费 | 中文字幕无码av波多野吉衣 | 午夜理论片yy44880影院 | 樱花草在线播放免费中文 | 精品国产福利一区二区 | 99久久99久久免费精品蜜桃 | 波多野结衣高清一区二区三区 | 国产色在线 | 国产 | 一本大道久久东京热无码av | 亚洲国产精品久久人人爱 | 丝袜足控一区二区三区 | 亚洲一区二区三区在线观看网站 | 久久成人a毛片免费观看网站 | 午夜理论片yy44880影院 | 精品午夜福利在线观看 | 熟妇人妻无码xxx视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 在线a亚洲视频播放在线观看 | 人人爽人人澡人人人妻 | 人人澡人人妻人人爽人人蜜桃 | 久久精品女人天堂av免费观看 | 国产av人人夜夜澡人人爽麻豆 | 国产av久久久久精东av | 又湿又紧又大又爽a视频国产 | 天海翼激烈高潮到腰振不止 | 久9re热视频这里只有精品 | 夜夜高潮次次欢爽av女 | 日本高清一区免费中文视频 | 东京一本一道一二三区 | 国产va免费精品观看 | 牲欲强的熟妇农村老妇女 | 中文字幕无码免费久久9一区9 | 色婷婷综合激情综在线播放 | 亚洲理论电影在线观看 | 国产av一区二区三区最新精品 | 99久久久国产精品无码免费 | 爽爽影院免费观看 | 澳门永久av免费网站 | 99久久无码一区人妻 | 国产精品无码成人午夜电影 | 人人妻人人澡人人爽欧美一区九九 | 国产成人一区二区三区别 | 日产精品99久久久久久 | 久久久久久亚洲精品a片成人 | 精品偷拍一区二区三区在线看 | 欧美丰满老熟妇xxxxx性 | 久久精品人人做人人综合 | 精品人人妻人人澡人人爽人人 | 亚洲高清偷拍一区二区三区 | 午夜精品久久久久久久久 | 久久国产精品偷任你爽任你 | 99久久人妻精品免费二区 | 三上悠亚人妻中文字幕在线 | 人妻少妇精品无码专区动漫 | 欧美喷潮久久久xxxxx | √天堂中文官网8在线 | 国内揄拍国内精品少妇国语 | 一本精品99久久精品77 | 亚洲欧洲日本无在线码 | 久久99精品久久久久久 | 天堂一区人妻无码 | 一区二区传媒有限公司 | 久久久久人妻一区精品色欧美 | 国产人成高清在线视频99最全资源 | 国产av无码专区亚洲awww | 十八禁视频网站在线观看 | 亚洲啪av永久无码精品放毛片 | 夜精品a片一区二区三区无码白浆 | 亚洲a无码综合a国产av中文 | 国内少妇偷人精品视频 | 日产精品99久久久久久 | 精品无人区无码乱码毛片国产 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲va欧美va天堂v国产综合 | 99久久精品无码一区二区毛片 | 国产免费久久久久久无码 | 国产精品久久久久久无码 | 高潮喷水的毛片 | 亚洲一区二区三区含羞草 | 熟妇人妻无乱码中文字幕 | 色妞www精品免费视频 | 日日躁夜夜躁狠狠躁 | 国产亚洲tv在线观看 | 欧美freesex黑人又粗又大 | 牲欲强的熟妇农村老妇女 | 狠狠躁日日躁夜夜躁2020 | 成人精品天堂一区二区三区 | 亚洲一区二区三区国产精华液 | 特大黑人娇小亚洲女 | 亚洲熟妇色xxxxx亚洲 | 综合人妻久久一区二区精品 | 日本www一道久久久免费榴莲 | 久久99精品国产.久久久久 | 国产激情一区二区三区 | 日韩精品一区二区av在线 | 国产女主播喷水视频在线观看 | 欧美性猛交xxxx富婆 | 熟妇人妻中文av无码 | 性色欲情网站iwww九文堂 | 亚洲国产精品无码一区二区三区 | 亚洲精品国产精品乱码视色 | 日日夜夜撸啊撸 | 77777熟女视频在线观看 а天堂中文在线官网 | 免费无码午夜福利片69 | 中文字幕乱码亚洲无线三区 | 熟妇人妻中文av无码 | 人人妻人人藻人人爽欧美一区 | 中文字幕人成乱码熟女app | 免费中文字幕日韩欧美 | 欧美真人作爱免费视频 | 亚洲国产精品无码一区二区三区 | 国产精品久久久久久久影院 | 窝窝午夜理论片影院 | 亚洲成a人片在线观看日本 | 国产精品久久久av久久久 | 午夜免费福利小电影 | 亚洲の无码国产の无码步美 | 久久精品国产精品国产精品污 | 久久精品国产一区二区三区 | 人人爽人人爽人人片av亚洲 | 正在播放老肥熟妇露脸 | 久久午夜无码鲁丝片午夜精品 | 国产精品无码永久免费888 | 奇米影视888欧美在线观看 | 黑森林福利视频导航 | 亚洲狠狠色丁香婷婷综合 | 国产精品人妻一区二区三区四 | 欧美成人高清在线播放 | 日韩人妻无码中文字幕视频 | 国产精品成人av在线观看 | 久久久中文字幕日本无吗 | 一本色道久久综合狠狠躁 | 国产麻豆精品精东影业av网站 | 少妇久久久久久人妻无码 | 内射巨臀欧美在线视频 | 中国女人内谢69xxxx | 天天综合网天天综合色 | 亚洲一区二区三区 | 国产人妻久久精品二区三区老狼 | ass日本丰满熟妇pics | 无遮无挡爽爽免费视频 | 国产精品a成v人在线播放 | 久久久精品成人免费观看 | 亚洲欧美国产精品专区久久 | 我要看www免费看插插视频 | 久久这里只有精品视频9 | 午夜无码区在线观看 | 人人妻人人澡人人爽人人精品 | 日本一区二区三区免费播放 | 精品久久久久久人妻无码中文字幕 | 久久亚洲中文字幕精品一区 | 小鲜肉自慰网站xnxx | 少妇太爽了在线观看 | 九九热爱视频精品 | 午夜精品久久久内射近拍高清 | аⅴ资源天堂资源库在线 | 久久熟妇人妻午夜寂寞影院 | 亚洲小说春色综合另类 | 人人妻人人藻人人爽欧美一区 | 内射老妇bbwx0c0ck | 午夜精品一区二区三区在线观看 | 久久精品一区二区三区四区 | 国产精品高潮呻吟av久久 | 亚洲中文字幕av在天堂 | 国产尤物精品视频 | 欧美熟妇另类久久久久久不卡 | 久久99精品久久久久久 | 人人妻人人澡人人爽欧美精品 | 亚洲色偷偷偷综合网 | 99er热精品视频 | 久久精品人人做人人综合 | 麻豆蜜桃av蜜臀av色欲av | 内射白嫩少妇超碰 | 国产精品资源一区二区 | 国产精品理论片在线观看 | 色欲综合久久中文字幕网 | 又粗又大又硬毛片免费看 | 天堂亚洲免费视频 | 欧美国产日韩亚洲中文 | 国产无遮挡吃胸膜奶免费看 | 国产色精品久久人妻 | 国产精品二区一区二区aⅴ污介绍 | 正在播放老肥熟妇露脸 | 一本一道久久综合久久 | 久精品国产欧美亚洲色aⅴ大片 | 欧美zoozzooz性欧美 | 乱码av麻豆丝袜熟女系列 | 日本欧美一区二区三区乱码 | 免费网站看v片在线18禁无码 | 久久久婷婷五月亚洲97号色 | 亚洲中文字幕乱码av波多ji | 亚洲精品成人福利网站 | 精品国偷自产在线 | 内射老妇bbwx0c0ck | 色婷婷综合中文久久一本 | 国产一精品一av一免费 | 性生交大片免费看l | 青春草在线视频免费观看 | 色窝窝无码一区二区三区色欲 | 中文字幕人妻无码一区二区三区 | 久久亚洲精品中文字幕无男同 | 久久综合狠狠综合久久综合88 | 久久久精品成人免费观看 | 久久精品国产日本波多野结衣 | 欧美亚洲国产一区二区三区 | 久久99热只有频精品8 | 最近免费中文字幕中文高清百度 | 激情综合激情五月俺也去 | 天堂无码人妻精品一区二区三区 | 网友自拍区视频精品 | 老太婆性杂交欧美肥老太 | 亚洲精品午夜无码电影网 | 久9re热视频这里只有精品 | 午夜无码区在线观看 | 日韩精品乱码av一区二区 | 国产精品久久久久影院嫩草 | 国产精品无码成人午夜电影 | 99精品视频在线观看免费 | 久久精品人人做人人综合 | 7777奇米四色成人眼影 | 丰满肥臀大屁股熟妇激情视频 | 日韩人妻无码中文字幕视频 | 成 人 免费观看网站 | 国产口爆吞精在线视频 | 国産精品久久久久久久 | 高清不卡一区二区三区 | 欧美 日韩 亚洲 在线 | 日本在线高清不卡免费播放 | 久久99精品久久久久久动态图 | 国产绳艺sm调教室论坛 | 日欧一片内射va在线影院 | 日韩精品无码一本二本三本色 | аⅴ资源天堂资源库在线 | 内射白嫩少妇超碰 | 国产亚洲精品久久久久久国模美 | 老司机亚洲精品影院无码 | 亚洲欧美中文字幕5发布 | 国产成人精品优优av | 天天摸天天碰天天添 | 亚洲第一网站男人都懂 | 人妻少妇精品无码专区二区 | 日日躁夜夜躁狠狠躁 | 久久久精品人妻久久影视 | 亚洲日韩av一区二区三区中文 | 欧美丰满老熟妇xxxxx性 | www成人国产高清内射 | 免费国产成人高清在线观看网站 | 国产精品鲁鲁鲁 | 国产69精品久久久久app下载 | 一个人免费观看的www视频 | 老司机亚洲精品影院无码 | a片免费视频在线观看 | 乱码午夜-极国产极内射 | 波多野结衣 黑人 | 国产莉萝无码av在线播放 | 成人女人看片免费视频放人 | 天干天干啦夜天干天2017 | 久久精品视频在线看15 | 樱花草在线播放免费中文 | 久久久久久国产精品无码下载 | 久久综合九色综合97网 | 色欲综合久久中文字幕网 | 免费人成网站视频在线观看 | 成人片黄网站色大片免费观看 | 好爽又高潮了毛片免费下载 | 日韩av无码中文无码电影 | 久久久精品国产sm最大网站 | √天堂资源地址中文在线 | 欧美熟妇另类久久久久久不卡 | 亚洲一区av无码专区在线观看 | 麻豆果冻传媒2021精品传媒一区下载 | а√资源新版在线天堂 | 美女扒开屁股让男人桶 | 久久精品99久久香蕉国产色戒 | 给我免费的视频在线观看 | 18禁黄网站男男禁片免费观看 | 99久久99久久免费精品蜜桃 | 人妻与老人中文字幕 | 国产激情一区二区三区 | 国产亚洲精品久久久久久久 | 国产精品亚洲а∨无码播放麻豆 | 欧美国产日韩久久mv | 久久国产精品偷任你爽任你 | 国产亚洲tv在线观看 | 97夜夜澡人人双人人人喊 | 久久久久免费看成人影片 | 帮老师解开蕾丝奶罩吸乳网站 | 精品乱码久久久久久久 | 亚洲中文字幕在线无码一区二区 | 大肉大捧一进一出视频出来呀 | 国产手机在线αⅴ片无码观看 | 蜜桃无码一区二区三区 | 国产av无码专区亚洲a∨毛片 | 男人的天堂2018无码 | 亚洲欧洲日本综合aⅴ在线 | 无码国产激情在线观看 | 人人超人人超碰超国产 | 老头边吃奶边弄进去呻吟 | 牲欲强的熟妇农村老妇女 | 人人妻人人澡人人爽精品欧美 | 中文字幕无线码 | 最近免费中文字幕中文高清百度 | 男女超爽视频免费播放 | 国产肉丝袜在线观看 | 永久免费精品精品永久-夜色 | 欧美35页视频在线观看 | 无码国产激情在线观看 | 亚洲中文字幕av在天堂 | 亚洲欧洲无卡二区视頻 | 欧美人与物videos另类 | 牛和人交xxxx欧美 | 精品国偷自产在线视频 | 久久人人97超碰a片精品 | 老子影院午夜伦不卡 | 四虎影视成人永久免费观看视频 | 日韩亚洲欧美中文高清在线 | 日本www一道久久久免费榴莲 | 麻豆蜜桃av蜜臀av色欲av | 水蜜桃av无码 | 女人被爽到呻吟gif动态图视看 | 日日躁夜夜躁狠狠躁 | 久久久久99精品成人片 | 亚洲熟妇自偷自拍另类 | 波多野结衣av在线观看 | 亚洲经典千人经典日产 | 日日躁夜夜躁狠狠躁 | 国产精品久久久久9999小说 | 扒开双腿疯狂进出爽爽爽视频 | 国产精品无码一区二区桃花视频 | 国产免费久久精品国产传媒 | 国产无遮挡又黄又爽又色 | 午夜精品一区二区三区在线观看 | 国产精品亚洲五月天高清 | 一本精品99久久精品77 | 永久免费精品精品永久-夜色 | 亚洲一区二区三区播放 | 国产99久久精品一区二区 | 成人亚洲精品久久久久软件 | 99久久久无码国产精品免费 | 亚洲欧美日韩成人高清在线一区 | 国产手机在线αⅴ片无码观看 | 成人av无码一区二区三区 | 国产乱人伦偷精品视频 | 久久人人97超碰a片精品 | 国产亚洲精品久久久久久 | 久青草影院在线观看国产 | 精品日本一区二区三区在线观看 | 亚洲中文字幕乱码av波多ji | 亚洲国产欧美国产综合一区 | 精品国产国产综合精品 | 国产亚av手机在线观看 | 久久久久久av无码免费看大片 | 99精品视频在线观看免费 | 国产精品美女久久久久av爽李琼 | 精品日本一区二区三区在线观看 | 色偷偷人人澡人人爽人人模 | 国产亚洲日韩欧美另类第八页 | 东京一本一道一二三区 | 一本久道久久综合婷婷五月 | 国产成人无码专区 | 天天燥日日燥 | 国产办公室秘书无码精品99 | 亚洲国产午夜精品理论片 | 亚洲狠狠色丁香婷婷综合 | 日本高清一区免费中文视频 | 亚洲一区二区三区偷拍女厕 | 亚洲自偷精品视频自拍 | 久久婷婷五月综合色国产香蕉 | 青青草原综合久久大伊人精品 | 99精品国产综合久久久久五月天 | 精品国产乱码久久久久乱码 | 狠狠色噜噜狠狠狠狠7777米奇 | 日本又色又爽又黄的a片18禁 | 女人被男人躁得好爽免费视频 | 日本护士xxxxhd少妇 | 久久久国产一区二区三区 | 精品久久久中文字幕人妻 | 亚洲欧美中文字幕5发布 | 久久精品国产精品国产精品污 | 欧美精品国产综合久久 | 荫蒂添的好舒服视频囗交 | 国产精品久久久久久亚洲影视内衣 | 中文字幕乱码人妻无码久久 | 国产精品久久久久9999小说 | ass日本丰满熟妇pics | 精品无码国产自产拍在线观看蜜 | 亚洲成av人影院在线观看 | 国精产品一区二区三区 | 久久国产精品精品国产色婷婷 | 思思久久99热只有频精品66 | 色一情一乱一伦一视频免费看 | 国产激情精品一区二区三区 | 欧美精品免费观看二区 | 国产精品香蕉在线观看 | 嫩b人妻精品一区二区三区 | 亚洲伊人久久精品影院 | 天下第一社区视频www日本 | 亚洲一区二区三区香蕉 | 97精品国产97久久久久久免费 | 18精品久久久无码午夜福利 | 精品一区二区三区波多野结衣 | 国产真实夫妇视频 | 最新国产麻豆aⅴ精品无码 | 青青青手机频在线观看 | 久久久中文久久久无码 | 欧美喷潮久久久xxxxx | 国产精品沙发午睡系列 | 久久无码人妻影院 | 亚洲中文字幕无码中字 | 国产亚洲精品久久久闺蜜 | 久久久久久久久888 | 四虎4hu永久免费 | 欧美亚洲日韩国产人成在线播放 | 任你躁国产自任一区二区三区 | 丰满人妻翻云覆雨呻吟视频 | 国精产品一品二品国精品69xx | 亚洲自偷自偷在线制服 | 久久精品中文闷骚内射 | 东京热一精品无码av | 久久精品国产大片免费观看 | 99精品国产综合久久久久五月天 | 在线精品亚洲一区二区 | 捆绑白丝粉色jk震动捧喷白浆 | 99麻豆久久久国产精品免费 | 国产精品亚洲一区二区三区喷水 | 欧美乱妇无乱码大黄a片 | 清纯唯美经典一区二区 | 骚片av蜜桃精品一区 | aa片在线观看视频在线播放 | 日本大香伊一区二区三区 | 亚洲国产av精品一区二区蜜芽 | 中文字幕日韩精品一区二区三区 | 亚洲 欧美 激情 小说 另类 | 国产免费观看黄av片 | 18禁黄网站男男禁片免费观看 | 东京热一精品无码av | 无人区乱码一区二区三区 | 狠狠躁日日躁夜夜躁2020 | 男女猛烈xx00免费视频试看 | 麻豆精产国品 | av香港经典三级级 在线 | 夜夜影院未满十八勿进 | 欧美激情综合亚洲一二区 | 国产成人综合在线女婷五月99播放 | 奇米影视888欧美在线观看 | 啦啦啦www在线观看免费视频 | 99精品无人区乱码1区2区3区 | v一区无码内射国产 | 两性色午夜免费视频 | 3d动漫精品啪啪一区二区中 | 无遮挡国产高潮视频免费观看 | 无码人妻出轨黑人中文字幕 | 欧美一区二区三区视频在线观看 | 国产精品久久久久久久影院 | 最新国产麻豆aⅴ精品无码 | 成人片黄网站色大片免费观看 | 精品欧洲av无码一区二区三区 | 牲交欧美兽交欧美 | 欧美日本免费一区二区三区 | 亚洲国精产品一二二线 | 国产成人久久精品流白浆 | 国产乱码精品一品二品 | 午夜精品一区二区三区在线观看 | 波多野结衣乳巨码无在线观看 | 蜜臀av在线播放 久久综合激激的五月天 | 欧美日韩综合一区二区三区 | 青春草在线视频免费观看 | 亚洲日韩av片在线观看 | 亚洲国产精品一区二区第一页 | 欧美性黑人极品hd | 精品久久久无码人妻字幂 | 性欧美牲交xxxxx视频 | 狠狠色丁香久久婷婷综合五月 | 欧洲熟妇色 欧美 | 7777奇米四色成人眼影 | 国产在热线精品视频 | 色综合久久久久综合一本到桃花网 | 国产成人久久精品流白浆 | 国产日产欧产精品精品app | 国语自产偷拍精品视频偷 | 两性色午夜免费视频 | 在线成人www免费观看视频 | 成人欧美一区二区三区 | 300部国产真实乱 | 日本丰满熟妇videos | 暴力强奷在线播放无码 | 人妻天天爽夜夜爽一区二区 | 影音先锋中文字幕无码 | 免费视频欧美无人区码 | av无码不卡在线观看免费 | 亚洲 另类 在线 欧美 制服 | 大肉大捧一进一出好爽视频 | 国产亚洲精品久久久ai换 | 免费男性肉肉影院 | 国内少妇偷人精品视频 | 国产成人精品三级麻豆 | 男女作爱免费网站 | 我要看www免费看插插视频 | 日日噜噜噜噜夜夜爽亚洲精品 | 丁香花在线影院观看在线播放 | av人摸人人人澡人人超碰下载 | 国产精品对白交换视频 | 久久99精品国产.久久久久 | 55夜色66夜色国产精品视频 | 欧美自拍另类欧美综合图片区 | 秋霞成人午夜鲁丝一区二区三区 | 中文精品无码中文字幕无码专区 | 成 人 网 站国产免费观看 | 国产精品久久久一区二区三区 | 真人与拘做受免费视频一 | 免费无码的av片在线观看 | 精品久久久久久亚洲精品 | 四十如虎的丰满熟妇啪啪 | 无码国模国产在线观看 | 亚洲第一网站男人都懂 | 亚洲色大成网站www国产 | 国产精品久久国产三级国 | 宝宝好涨水快流出来免费视频 | 一本无码人妻在中文字幕免费 | 午夜免费福利小电影 | 国产黄在线观看免费观看不卡 | 国产精品久久久久久久9999 | 在线播放亚洲第一字幕 | 国产乱人伦av在线无码 | 无码av免费一区二区三区试看 | 久久精品女人天堂av免费观看 | 国产真实乱对白精彩久久 | 国色天香社区在线视频 | 男人的天堂av网站 | 亚洲中文字幕成人无码 | 丰满人妻被黑人猛烈进入 | 国产超碰人人爽人人做人人添 | 中文字幕精品av一区二区五区 | 久久99精品国产麻豆 | 色五月丁香五月综合五月 | 亚洲の无码国产の无码步美 | 亚洲精品鲁一鲁一区二区三区 | 国产电影无码午夜在线播放 | 久久精品无码一区二区三区 | 免费男性肉肉影院 | 色综合久久久无码中文字幕 | 亚洲熟妇色xxxxx欧美老妇y | 国产极品美女高潮无套在线观看 | 精品熟女少妇av免费观看 | 欧美 日韩 亚洲 在线 | 精品国产成人一区二区三区 | 天堂一区人妻无码 | 少妇邻居内射在线 | 人人澡人摸人人添 | 久久国内精品自在自线 | 奇米影视7777久久精品人人爽 | 波多野结衣一区二区三区av免费 | 亚洲第一网站男人都懂 | 亚洲日韩一区二区三区 | 欧美老妇与禽交 | а√资源新版在线天堂 | 亚洲自偷自偷在线制服 | 亚洲国产精品无码一区二区三区 | 高清无码午夜福利视频 | 色诱久久久久综合网ywww | 国产超碰人人爽人人做人人添 | 国产av剧情md精品麻豆 | 日日噜噜噜噜夜夜爽亚洲精品 | 久久精品国产99久久6动漫 | 国产农村乱对白刺激视频 | 国产热a欧美热a在线视频 | 男人的天堂av网站 | 中文字幕 亚洲精品 第1页 | 熟妇人妻中文av无码 | 极品尤物被啪到呻吟喷水 | 色窝窝无码一区二区三区色欲 | 少妇性l交大片欧洲热妇乱xxx | 亚洲狠狠色丁香婷婷综合 | 国产人妻精品午夜福利免费 | 亚洲va中文字幕无码久久不卡 | 强伦人妻一区二区三区视频18 | 啦啦啦www在线观看免费视频 | 搡女人真爽免费视频大全 | 久久综合狠狠综合久久综合88 | 一本大道久久东京热无码av | 又粗又大又硬又长又爽 | 狠狠噜狠狠狠狠丁香五月 | 亚洲精品一区二区三区大桥未久 | 成人欧美一区二区三区黑人免费 | 色综合久久久久综合一本到桃花网 | 成人毛片一区二区 | 国产精品久久久 | 久久精品国产一区二区三区 | 精品欧美一区二区三区久久久 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 日韩少妇内射免费播放 | 2020久久超碰国产精品最新 | 噜噜噜亚洲色成人网站 | 亚洲熟妇自偷自拍另类 | 免费观看又污又黄的网站 | 亚洲乱码中文字幕在线 | 国产成人av免费观看 | 亚洲精品鲁一鲁一区二区三区 | 国产后入清纯学生妹 | 奇米影视7777久久精品人人爽 | 精品乱子伦一区二区三区 | 久久99精品国产麻豆蜜芽 | 国产欧美熟妇另类久久久 | 成人亚洲精品久久久久 | 成人亚洲精品久久久久 | 国产免费久久精品国产传媒 | 永久免费观看国产裸体美女 | 欧美国产日产一区二区 | 99久久99久久免费精品蜜桃 | 欧美怡红院免费全部视频 | 未满小14洗澡无码视频网站 | 丝袜足控一区二区三区 | 97久久精品无码一区二区 | 久久精品国产99精品亚洲 | 在线播放亚洲第一字幕 | 99er热精品视频 | 欧美熟妇另类久久久久久多毛 | 亚洲欧洲中文日韩av乱码 | 伦伦影院午夜理论片 | 国产精品久久久久久亚洲影视内衣 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 疯狂三人交性欧美 | 亚洲 欧美 激情 小说 另类 | www成人国产高清内射 | 午夜福利不卡在线视频 | 中文字幕精品av一区二区五区 | 亚洲日韩中文字幕在线播放 | 精品水蜜桃久久久久久久 | 亚洲综合色区中文字幕 | av无码不卡在线观看免费 | 高中生自慰www网站 | 亚洲s码欧洲m码国产av | 一本色道久久综合狠狠躁 | 18精品久久久无码午夜福利 | 蜜桃臀无码内射一区二区三区 | 国产精品丝袜黑色高跟鞋 | 无码国产色欲xxxxx视频 | 久久久久久av无码免费看大片 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 九九在线中文字幕无码 | 1000部啪啪未满十八勿入下载 | 高清无码午夜福利视频 | 激情综合激情五月俺也去 | 亚洲精品国产精品乱码视色 | yw尤物av无码国产在线观看 | 黑人粗大猛烈进出高潮视频 | 久久婷婷五月综合色国产香蕉 | 76少妇精品导航 | 国产亚洲精品久久久久久大师 | 亚洲国产精品一区二区美利坚 | 国产精品99爱免费视频 | 天天拍夜夜添久久精品大 | 久久久av男人的天堂 | 久久久久av无码免费网 | av香港经典三级级 在线 | 一本久道高清无码视频 | 国产精品无码一区二区三区不卡 | 三级4级全黄60分钟 | 国产9 9在线 | 中文 | 久久久久亚洲精品中文字幕 | 亚洲娇小与黑人巨大交 | 无码乱肉视频免费大全合集 | 日韩视频 中文字幕 视频一区 | 性欧美牲交在线视频 | 爱做久久久久久 | 日韩精品久久久肉伦网站 | 成人综合网亚洲伊人 | 日韩精品久久久肉伦网站 | 久久精品国产日本波多野结衣 | 一区二区传媒有限公司 | 久久亚洲a片com人成 | 无码人妻丰满熟妇区毛片18 | 国产av无码专区亚洲awww | 亚洲精品国产精品乱码视色 | 国产欧美精品一区二区三区 | 色综合久久久久综合一本到桃花网 | 中文毛片无遮挡高清免费 | 久久精品国产亚洲精品 | 国产精品久久久久无码av色戒 | 水蜜桃亚洲一二三四在线 | 偷窥村妇洗澡毛毛多 | 红桃av一区二区三区在线无码av | 午夜时刻免费入口 | 1000部啪啪未满十八勿入下载 | 一本色道久久综合狠狠躁 | 亚洲精品一区二区三区在线 | 亚洲精品久久久久久一区二区 | 亚洲精品中文字幕 | 久久99精品久久久久久动态图 | 国产成人精品视频ⅴa片软件竹菊 | 又色又爽又黄的美女裸体网站 | 亚洲码国产精品高潮在线 | 久久精品人人做人人综合 | 欧美日韩一区二区三区自拍 | 在线播放亚洲第一字幕 | 国产免费久久久久久无码 | 国产精品高潮呻吟av久久 | 久激情内射婷内射蜜桃人妖 | 成年美女黄网站色大免费视频 | 国产精品亚洲一区二区三区喷水 | 亚洲成av人片天堂网无码】 | 日韩欧美群交p片內射中文 | 国产精品鲁鲁鲁 | 小sao货水好多真紧h无码视频 | 亚洲の无码国产の无码步美 | 熟女体下毛毛黑森林 | 国产免费无码一区二区视频 | 日韩成人一区二区三区在线观看 | 奇米影视7777久久精品人人爽 | 欧美 亚洲 国产 另类 | 精品国产aⅴ无码一区二区 | 成人欧美一区二区三区黑人 | 久久成人a毛片免费观看网站 | 伊人久久大香线蕉亚洲 | 三上悠亚人妻中文字幕在线 | 亚洲啪av永久无码精品放毛片 | 亚洲中文字幕无码中文字在线 | 欧美熟妇另类久久久久久不卡 | av小次郎收藏 | 欧美喷潮久久久xxxxx | 97无码免费人妻超级碰碰夜夜 | 蜜桃无码一区二区三区 | 日本精品少妇一区二区三区 | 国产熟女一区二区三区四区五区 | 亚洲一区二区三区 | 欧美人与牲动交xxxx | 国産精品久久久久久久 | 欧美喷潮久久久xxxxx | 鲁一鲁av2019在线 | 亚洲日韩一区二区 | 亚洲第一网站男人都懂 | 日本一区二区三区免费高清 | 久久精品人人做人人综合试看 | 免费看男女做好爽好硬视频 | 久久国产自偷自偷免费一区调 | 精品aⅴ一区二区三区 | 男女猛烈xx00免费视频试看 | 欧美大屁股xxxxhd黑色 | 中国女人内谢69xxxxxa片 | 亚洲の无码国产の无码影院 | 中文字幕乱妇无码av在线 | 夫妻免费无码v看片 | 国产精品-区区久久久狼 | 亚洲国产精品无码久久久久高潮 | 成人免费无码大片a毛片 | 色欲人妻aaaaaaa无码 | 少妇愉情理伦片bd | 久久久久久久女国产乱让韩 | 少妇人妻大乳在线视频 | 狠狠色噜噜狠狠狠7777奇米 | 波多野结衣av一区二区全免费观看 | 国产在线一区二区三区四区五区 | 熟妇女人妻丰满少妇中文字幕 | 波多野结衣乳巨码无在线观看 | 大屁股大乳丰满人妻 | 亚洲中文字幕无码一久久区 | 伊人久久大香线蕉午夜 | 日本大乳高潮视频在线观看 | 女高中生第一次破苞av | 少妇性俱乐部纵欲狂欢电影 | 乌克兰少妇xxxx做受 | 成人三级无码视频在线观看 | 久久久久亚洲精品男人的天堂 | 无码人妻出轨黑人中文字幕 | 亚洲国产av精品一区二区蜜芽 | 久久国内精品自在自线 | 欧洲精品码一区二区三区免费看 | 国产综合色产在线精品 | 亚洲色大成网站www | 在线播放无码字幕亚洲 | 亚洲成a人片在线观看日本 | 亚洲最大成人网站 | 亚洲春色在线视频 | 日欧一片内射va在线影院 | 成人亚洲精品久久久久 | 娇妻被黑人粗大高潮白浆 | 噜噜噜亚洲色成人网站 | 国内精品九九久久久精品 | 亚洲欧美国产精品专区久久 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 99久久久国产精品无码免费 | 亚洲乱码日产精品bd | 国产精品久久久 | 内射老妇bbwx0c0ck | 婷婷丁香六月激情综合啪 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 国产精品高潮呻吟av久久 | 97久久国产亚洲精品超碰热 | 精品无码一区二区三区的天堂 | 少妇久久久久久人妻无码 | 国产后入清纯学生妹 | 香港三级日本三级妇三级 | 欧美freesex黑人又粗又大 | 国产精品亚洲а∨无码播放麻豆 | 国产精品无码一区二区三区不卡 | 亚洲中文字幕乱码av波多ji | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 999久久久国产精品消防器材 | 青青青手机频在线观看 | 成人影院yy111111在线观看 | 国产熟妇另类久久久久 | 在教室伦流澡到高潮hnp视频 | 一区二区三区高清视频一 | 久久视频在线观看精品 | 国产精品久久久 | 久久成人a毛片免费观看网站 | 骚片av蜜桃精品一区 | 中文字幕 亚洲精品 第1页 | 国产精品a成v人在线播放 | 国产成人亚洲综合无码 | 少妇被黑人到高潮喷出白浆 | 蜜臀av无码人妻精品 | 亚洲小说春色综合另类 | 国产va免费精品观看 | 国产av人人夜夜澡人人爽麻豆 | 牲欲强的熟妇农村老妇女 | 国产精品久久久一区二区三区 | 沈阳熟女露脸对白视频 | aⅴ亚洲 日韩 色 图网站 播放 | 免费观看激色视频网站 | 国产精品久久久久久亚洲影视内衣 | 国产情侣作爱视频免费观看 | 无码av最新清无码专区吞精 | 国产情侣作爱视频免费观看 | 久久久久久九九精品久 | yw尤物av无码国产在线观看 | 亚洲精品久久久久中文第一幕 | 成人影院yy111111在线观看 | 午夜无码人妻av大片色欲 | 中文无码成人免费视频在线观看 | 色一情一乱一伦一视频免费看 | 精品人人妻人人澡人人爽人人 | 清纯唯美经典一区二区 | 夜精品a片一区二区三区无码白浆 | 一二三四社区在线中文视频 | 撕开奶罩揉吮奶头视频 | 俄罗斯老熟妇色xxxx | 日本熟妇大屁股人妻 | 少妇人妻偷人精品无码视频 | 亚洲国产精品毛片av不卡在线 | 狂野欧美性猛xxxx乱大交 | 国产av无码专区亚洲a∨毛片 | 性做久久久久久久久 | 色综合久久久久综合一本到桃花网 | 无码人妻久久一区二区三区不卡 | 一本久道久久综合狠狠爱 | 精品国产一区二区三区四区 | 国产深夜福利视频在线 | 丰满人妻翻云覆雨呻吟视频 | 精品久久久久久亚洲精品 | 玩弄中年熟妇正在播放 | 国产特级毛片aaaaaaa高清 | 亚洲呦女专区 | 日韩av无码一区二区三区不卡 | 亚洲精品一区二区三区在线观看 | 国产乱码精品一品二品 | 欧美大屁股xxxxhd黑色 | 日本一卡二卡不卡视频查询 | 日韩人妻系列无码专区 | 又紧又大又爽精品一区二区 | 日日躁夜夜躁狠狠躁 | 亚洲精品中文字幕久久久久 | 亚洲精品一区国产 | 天天拍夜夜添久久精品大 | 中文字幕无码日韩专区 | 国产凸凹视频一区二区 | 樱花草在线播放免费中文 | 亚洲成av人片在线观看无码不卡 | 国产免费久久久久久无码 | 亚洲成av人在线观看网址 | 两性色午夜视频免费播放 | 日韩 欧美 动漫 国产 制服 | 精品日本一区二区三区在线观看 | 性色欲网站人妻丰满中文久久不卡 | 久久亚洲中文字幕精品一区 | 亚洲精品美女久久久久久久 | 欧美 日韩 人妻 高清 中文 | 国产在线一区二区三区四区五区 | 国产性生交xxxxx无码 | 少妇高潮喷潮久久久影院 | 中文字幕乱码亚洲无线三区 | 国产精品无码一区二区三区不卡 | 日本精品高清一区二区 | 自拍偷自拍亚洲精品10p | 亚洲乱码中文字幕在线 | 色婷婷av一区二区三区之红樱桃 | 国产成人精品必看 | 午夜理论片yy44880影院 | 色婷婷综合激情综在线播放 | 久久精品国产99精品亚洲 | 久久久久人妻一区精品色欧美 | 一二三四社区在线中文视频 | 狠狠躁日日躁夜夜躁2020 | 一个人看的视频www在线 | 亚洲综合无码一区二区三区 | 九九久久精品国产免费看小说 | 成 人 免费观看网站 | 狠狠躁日日躁夜夜躁2020 | 男女猛烈xx00免费视频试看 | 人人妻人人澡人人爽精品欧美 | 99精品视频在线观看免费 | 亚洲午夜久久久影院 | 国语自产偷拍精品视频偷 | 国产综合久久久久鬼色 | 正在播放老肥熟妇露脸 | 欧美zoozzooz性欧美 | 全黄性性激高免费视频 | 午夜精品久久久久久久久 | 亚洲国产精品无码一区二区三区 | 亚洲日韩中文字幕在线播放 | 蜜臀av在线播放 久久综合激激的五月天 | 人妻少妇被猛烈进入中文字幕 | 双乳奶水饱满少妇呻吟 | 欧美大屁股xxxxhd黑色 | 人妻少妇精品视频专区 | 久久国内精品自在自线 | 色婷婷综合中文久久一本 | 偷窥日本少妇撒尿chinese | 国产色视频一区二区三区 | 久久久久久久人妻无码中文字幕爆 | 久久久国产一区二区三区 | 国产精品二区一区二区aⅴ污介绍 | 精品欧美一区二区三区久久久 | 亚洲精品国产a久久久久久 | 扒开双腿疯狂进出爽爽爽视频 | 少妇性俱乐部纵欲狂欢电影 | 老头边吃奶边弄进去呻吟 | 国产精品资源一区二区 | 欧美亚洲日韩国产人成在线播放 | 日本精品高清一区二区 | 高潮毛片无遮挡高清免费视频 | 国产网红无码精品视频 | 欧美精品一区二区精品久久 | 成人影院yy111111在线观看 | 人妻与老人中文字幕 | 97精品国产97久久久久久免费 | 亚洲成色www久久网站 | 亚洲成熟女人毛毛耸耸多 | 青青久在线视频免费观看 | a片免费视频在线观看 | 国内精品人妻无码久久久影院 | 99精品国产综合久久久久五月天 | 精品国产福利一区二区 | 中文字幕无码热在线视频 | 99久久无码一区人妻 | 国产精品久久久久久无码 | 国产精品久免费的黄网站 | 两性色午夜视频免费播放 | 亚洲一区二区三区偷拍女厕 | 婷婷六月久久综合丁香 | 日日碰狠狠丁香久燥 | а√资源新版在线天堂 | 性色欲情网站iwww九文堂 | 国产在线无码精品电影网 | av无码久久久久不卡免费网站 | 亚洲国产欧美在线成人 | 2019午夜福利不卡片在线 | 亚洲爆乳精品无码一区二区三区 | 国产综合久久久久鬼色 | 丰满人妻被黑人猛烈进入 | 色狠狠av一区二区三区 | 色一情一乱一伦一区二区三欧美 | 国产九九九九九九九a片 | 久久97精品久久久久久久不卡 | 无码人妻av免费一区二区三区 | 国产乱人无码伦av在线a | 无码人妻av免费一区二区三区 | 亚洲中文字幕va福利 | 亚洲爆乳精品无码一区二区三区 | 国产色精品久久人妻 | 香蕉久久久久久av成人 | 午夜精品一区二区三区的区别 | 精品厕所偷拍各类美女tp嘘嘘 | 国产成人精品一区二区在线小狼 | 欧美第一黄网免费网站 | 牲交欧美兽交欧美 | 国产特级毛片aaaaaaa高清 | 久久久久亚洲精品男人的天堂 | 久久久久se色偷偷亚洲精品av | 亚洲欧美中文字幕5发布 | 成人无码视频在线观看网站 | 中文字幕乱妇无码av在线 | 国产精品18久久久久久麻辣 | 熟女少妇人妻中文字幕 | 内射欧美老妇wbb | 欧美激情一区二区三区成人 | 扒开双腿疯狂进出爽爽爽视频 | 无码人妻出轨黑人中文字幕 | 国产色xx群视频射精 | 亚洲精品国产a久久久久久 | 18精品久久久无码午夜福利 | 精品国偷自产在线视频 | 久久久久久九九精品久 | 波多野结衣乳巨码无在线观看 | 国产精品亚洲lv粉色 | 欧美人与禽猛交狂配 | 伊人久久婷婷五月综合97色 | 亚洲精品久久久久久一区二区 | 97夜夜澡人人双人人人喊 | 国产精品对白交换视频 | 狠狠亚洲超碰狼人久久 | 两性色午夜免费视频 | 色一情一乱一伦一视频免费看 | 无码纯肉视频在线观看 | 少妇厨房愉情理9仑片视频 | 领导边摸边吃奶边做爽在线观看 | 娇妻被黑人粗大高潮白浆 | 欧美日本免费一区二区三区 | 国产成人精品无码播放 | 大肉大捧一进一出好爽视频 | 国产亚洲精品久久久久久久久动漫 | 色婷婷欧美在线播放内射 | 日本www一道久久久免费榴莲 | 亚洲国产精品成人久久蜜臀 | 国产内射老熟女aaaa | 亚欧洲精品在线视频免费观看 | 亚洲人成网站在线播放942 | 在线a亚洲视频播放在线观看 | 免费乱码人妻系列无码专区 | 人人妻人人澡人人爽欧美一区 | 亚洲日本在线电影 | 日欧一片内射va在线影院 | 亚洲日韩一区二区 | 福利一区二区三区视频在线观看 | 久久这里只有精品视频9 | 亚洲小说图区综合在线 | 99久久精品日本一区二区免费 | 婷婷丁香六月激情综合啪 | 色欲久久久天天天综合网精品 | 国产亚洲美女精品久久久2020 | 九九久久精品国产免费看小说 | 98国产精品综合一区二区三区 | 鲁大师影院在线观看 | 蜜桃臀无码内射一区二区三区 | 色综合久久久无码网中文 | 欧美阿v高清资源不卡在线播放 | 性色av无码免费一区二区三区 | 久久精品国产一区二区三区肥胖 | 人人妻人人澡人人爽精品欧美 | av小次郎收藏 | 一本色道久久综合狠狠躁 | 中文字幕av日韩精品一区二区 | 在线天堂新版最新版在线8 | 2019午夜福利不卡片在线 | 97久久精品无码一区二区 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 日韩精品无码免费一区二区三区 | 亚洲精品综合五月久久小说 | 中文字幕乱码亚洲无线三区 | 国产精品美女久久久网av | 国产一区二区三区精品视频 | 2019nv天堂香蕉在线观看 | 国产亚洲精品久久久闺蜜 | 色诱久久久久综合网ywww | 亚洲熟熟妇xxxx | 成人无码精品1区2区3区免费看 | 亚洲国产午夜精品理论片 | 中文字幕亚洲情99在线 | 人妻有码中文字幕在线 | 欧美亚洲日韩国产人成在线播放 | 亚洲日本在线电影 | 色狠狠av一区二区三区 | 国产内射老熟女aaaa | 131美女爱做视频 | 欧美野外疯狂做受xxxx高潮 | 大胆欧美熟妇xx | 波多野结衣乳巨码无在线观看 | 国产精品视频免费播放 | 熟女俱乐部五十路六十路av | 日本va欧美va欧美va精品 | 精品国精品国产自在久国产87 | 天天躁夜夜躁狠狠是什么心态 | 成人欧美一区二区三区 | 免费网站看v片在线18禁无码 | 欧美国产亚洲日韩在线二区 | 麻豆国产丝袜白领秘书在线观看 | 99久久精品日本一区二区免费 | 精品亚洲韩国一区二区三区 | 久久久精品国产sm最大网站 | 成熟人妻av无码专区 | 国产精品久久久久久久9999 | 一区二区三区高清视频一 | 亚洲日韩av一区二区三区四区 | 欧美激情一区二区三区成人 | 久久精品99久久香蕉国产色戒 | 亚洲一区二区三区无码久久 | 国产无套内射久久久国产 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 欧美刺激性大交 | 亚洲国产综合无码一区 | 久久国产36精品色熟妇 | 久久精品人妻少妇一区二区三区 | 丰满人妻翻云覆雨呻吟视频 | 欧美日韩人成综合在线播放 | 在线看片无码永久免费视频 | 免费看少妇作爱视频 | 国产综合在线观看 | 亚洲精品无码国产 | 日日鲁鲁鲁夜夜爽爽狠狠 | 高中生自慰www网站 | 亚洲精品成a人在线观看 | 最新版天堂资源中文官网 | 东京热一精品无码av | 欧美肥老太牲交大战 | 国产精品美女久久久网av | 欧美xxxx黑人又粗又长 | 久久99精品国产.久久久久 | 免费中文字幕日韩欧美 | 国产成人无码av一区二区 | 欧美日韩综合一区二区三区 | 亚洲国产日韩a在线播放 | 日本肉体xxxx裸交 | 午夜性刺激在线视频免费 | 亚洲综合另类小说色区 | 丝袜 中出 制服 人妻 美腿 | 无套内谢的新婚少妇国语播放 | 美女张开腿让人桶 | av无码电影一区二区三区 | 亚洲色欲色欲欲www在线 | 1000部啪啪未满十八勿入下载 | 中文字幕无码av波多野吉衣 | 欧洲欧美人成视频在线 | 扒开双腿疯狂进出爽爽爽视频 | 精品无码国产自产拍在线观看蜜 | 亚洲国产成人a精品不卡在线 | 人人超人人超碰超国产 | 一本色道久久综合亚洲精品不卡 | 亚洲自偷自偷在线制服 | 少妇被粗大的猛进出69影院 | 人妻中文无码久热丝袜 | 日韩精品成人一区二区三区 | 色欲综合久久中文字幕网 | 精品人妻中文字幕有码在线 | 老头边吃奶边弄进去呻吟 | 久久久www成人免费毛片 | 成人无码视频免费播放 | 亚洲人交乣女bbw | 国产性生大片免费观看性 | 国语精品一区二区三区 | 水蜜桃色314在线观看 | 少妇人妻偷人精品无码视频 | 国产亚洲欧美日韩亚洲中文色 | 国产精品无码永久免费888 | 色一情一乱一伦一视频免费看 | 麻豆国产人妻欲求不满谁演的 | 久久久国产一区二区三区 | 性欧美牲交在线视频 | 高清国产亚洲精品自在久久 | 少妇性l交大片 | 成人无码精品1区2区3区免费看 | 国产亚洲精品久久久ai换 | 亚洲精品午夜国产va久久成人 | 美女极度色诱视频国产 | 天堂а√在线中文在线 | 精品无码一区二区三区的天堂 | 日本熟妇乱子伦xxxx | 麻豆国产97在线 | 欧洲 | 亚洲精品成人av在线 | 国产熟女一区二区三区四区五区 | 国产精品人妻一区二区三区四 | 久久亚洲精品成人无码 | 欧美日韩一区二区三区自拍 | 鲁一鲁av2019在线 | 亚洲а∨天堂久久精品2021 | 国产超碰人人爽人人做人人添 | 成人免费视频一区二区 | 偷窥日本少妇撒尿chinese | 亚洲中文无码av永久不收费 | 成人无码视频免费播放 | 中文字幕无码免费久久99 | 日本护士xxxxhd少妇 | 丰腴饱满的极品熟妇 | 国产欧美精品一区二区三区 | 亚洲精品久久久久avwww潮水 | 中文精品久久久久人妻不卡 | 亚洲成av人影院在线观看 | 在线播放亚洲第一字幕 | 波多野结衣一区二区三区av免费 | 一本精品99久久精品77 | 在线播放免费人成毛片乱码 | 久久久精品欧美一区二区免费 | 亚洲欧美精品aaaaaa片 | 亚洲精品综合五月久久小说 | 国产卡一卡二卡三 | 精品无码一区二区三区爱欲 | 国产精品多人p群无码 | 一本色道婷婷久久欧美 | 亚洲精品一区二区三区在线 | 在线播放免费人成毛片乱码 | 色综合久久网 | 国产无遮挡又黄又爽免费视频 | 欧美熟妇另类久久久久久多毛 | 激情五月综合色婷婷一区二区 | 亚洲成色www久久网站 | 波多野结衣乳巨码无在线观看 | 国产精品.xx视频.xxtv | 国产亚洲精品久久久久久 | 国产一区二区三区日韩精品 | 日韩在线不卡免费视频一区 | 亚洲精品中文字幕 | 中文精品无码中文字幕无码专区 | 国产suv精品一区二区五 | 国产精品美女久久久 | 在线а√天堂中文官网 | 无码午夜成人1000部免费视频 | √8天堂资源地址中文在线 | 成 人影片 免费观看 | 18黄暴禁片在线观看 | 天海翼激烈高潮到腰振不止 | 亚洲va欧美va天堂v国产综合 | 人人澡人人妻人人爽人人蜜桃 | 中文字幕乱码人妻二区三区 | 无码纯肉视频在线观看 | 久久久久久久人妻无码中文字幕爆 | 国产偷国产偷精品高清尤物 | 99久久久无码国产精品免费 | 中文字幕人成乱码熟女app | 亚洲成av人片在线观看无码不卡 | 亚洲爆乳无码专区 | 99视频精品全部免费免费观看 | 老熟女乱子伦 | 午夜精品久久久久久久 | 丰满少妇人妻久久久久久 | 牲欲强的熟妇农村老妇女视频 | 18禁黄网站男男禁片免费观看 | 亚洲一区二区三区无码久久 | 国产亚洲人成a在线v网站 | 欧美性生交xxxxx久久久 | 无码人妻久久一区二区三区不卡 | 亚洲中文字幕成人无码 | 亚洲区欧美区综合区自拍区 | 亚洲精品中文字幕乱码 | 国产精品人人爽人人做我的可爱 | 成人毛片一区二区 | 67194成是人免费无码 | 性史性农村dvd毛片 | 女人被爽到呻吟gif动态图视看 | 精品 日韩 国产 欧美 视频 | 成人性做爰aaa片免费看不忠 | 亚洲欧美综合区丁香五月小说 | 樱花草在线播放免费中文 | 欧美zoozzooz性欧美 | 日本免费一区二区三区最新 | 久久亚洲日韩精品一区二区三区 | 午夜无码人妻av大片色欲 | 风流少妇按摩来高潮 | 中国大陆精品视频xxxx | 亚洲一区二区三区无码久久 | 成人无码视频在线观看网站 | 国产人妻人伦精品1国产丝袜 | 亚洲国产精品久久人人爱 | 久久久久亚洲精品中文字幕 | 四虎4hu永久免费 | 亚洲国产精品美女久久久久 | 东京一本一道一二三区 | 综合人妻久久一区二区精品 | 人妻尝试又大又粗久久 | 精品aⅴ一区二区三区 | 中文字幕人妻无码一区二区三区 | 欧洲熟妇精品视频 | 亚洲熟妇自偷自拍另类 | 少妇激情av一区二区 | 精品夜夜澡人妻无码av蜜桃 | 久久婷婷五月综合色国产香蕉 | 欧美国产日韩久久mv | 国产香蕉尹人视频在线 | 亚洲理论电影在线观看 | 国产艳妇av在线观看果冻传媒 | 亚洲精品久久久久久久久久久 | 日韩欧美中文字幕在线三区 | 国精产品一品二品国精品69xx | 国内揄拍国内精品少妇国语 | 成人无码精品一区二区三区 | 亚洲乱码国产乱码精品精 | 精品国产麻豆免费人成网站 | 国内精品人妻无码久久久影院蜜桃 | 成人一在线视频日韩国产 | 激情五月综合色婷婷一区二区 | 国产免费久久精品国产传媒 | 国产两女互慰高潮视频在线观看 | 成人精品视频一区二区 | 成人av无码一区二区三区 | 18禁止看的免费污网站 | 又粗又大又硬毛片免费看 | 樱花草在线播放免费中文 | 久久五月精品中文字幕 | 久久久久成人片免费观看蜜芽 | 人妻体内射精一区二区三四 | 国产9 9在线 | 中文 | 综合人妻久久一区二区精品 | av无码不卡在线观看免费 | 国产人妻大战黑人第1集 | 色欲人妻aaaaaaa无码 | 亚洲人成网站色7799 | 香蕉久久久久久av成人 | 国产人妻精品午夜福利免费 | 欧美一区二区三区 | 丰满护士巨好爽好大乳 | 国产片av国语在线观看 | 亚洲熟女一区二区三区 | 少妇被黑人到高潮喷出白浆 | 精品一区二区不卡无码av | 极品尤物被啪到呻吟喷水 | 亚洲第一无码av无码专区 | 少妇激情av一区二区 | 欧美三级a做爰在线观看 | 人妻熟女一区 | 亚洲精品国偷拍自产在线麻豆 | 久久久精品国产sm最大网站 | 99久久精品国产一区二区蜜芽 | 国产精品视频免费播放 | 成人一区二区免费视频 | 国产成人无码av一区二区 | 成人一区二区免费视频 | 丰满妇女强制高潮18xxxx | 中文字幕无线码免费人妻 | 国产成人无码午夜视频在线观看 | 无码国内精品人妻少妇 | 四虎影视成人永久免费观看视频 | 又大又紧又粉嫩18p少妇 | 精品久久久久久人妻无码中文字幕 | 性做久久久久久久免费看 | 18精品久久久无码午夜福利 | 亚洲日本va午夜在线电影 | 日韩精品无码一区二区中文字幕 | 高中生自慰www网站 | 久久精品国产精品国产精品污 | 日本在线高清不卡免费播放 | 国产做国产爱免费视频 | 伊人久久大香线蕉亚洲 | 免费无码午夜福利片69 | 青草视频在线播放 | 妺妺窝人体色www在线小说 | 成人av无码一区二区三区 | 亚洲精品一区二区三区在线 | 亚洲成熟女人毛毛耸耸多 | 国产麻豆精品精东影业av网站 | 97色伦图片97综合影院 | 色 综合 欧美 亚洲 国产 | 精品午夜福利在线观看 | 亚洲精品一区三区三区在线观看 | 日日摸夜夜摸狠狠摸婷婷 | 国产在线精品一区二区三区直播 | 伊人色综合久久天天小片 | 亚洲欧美国产精品专区久久 | 精品亚洲成av人在线观看 | 久久精品国产99精品亚洲 | 无套内射视频囯产 | 狠狠色噜噜狠狠狠7777奇米 | 亚洲乱码中文字幕在线 | 精品午夜福利在线观看 | 亲嘴扒胸摸屁股激烈网站 | 日韩人妻系列无码专区 | 国产色视频一区二区三区 | 一本久道久久综合婷婷五月 | 成人精品视频一区二区三区尤物 | 人妻aⅴ无码一区二区三区 | 亚洲成a人片在线观看无码3d | 蜜桃视频插满18在线观看 | 日韩欧美群交p片內射中文 | 色五月五月丁香亚洲综合网 | 午夜肉伦伦影院 | 欧美黑人乱大交 | 日本精品少妇一区二区三区 | 日本熟妇乱子伦xxxx | 中文毛片无遮挡高清免费 | 日日躁夜夜躁狠狠躁 | 九九热爱视频精品 | 纯爱无遮挡h肉动漫在线播放 | 国产精品嫩草久久久久 | 国产午夜亚洲精品不卡 | 18无码粉嫩小泬无套在线观看 | 国产成人无码一二三区视频 | 亚洲欧洲无卡二区视頻 | 久久无码中文字幕免费影院蜜桃 | 免费国产黄网站在线观看 | 极品嫩模高潮叫床 | 内射老妇bbwx0c0ck | 麻豆果冻传媒2021精品传媒一区下载 | 欧美丰满少妇xxxx性 | 国产精华av午夜在线观看 | 国产av一区二区精品久久凹凸 | www国产亚洲精品久久网站 | 国产精品成人av在线观看 | 免费乱码人妻系列无码专区 | 娇妻被黑人粗大高潮白浆 | 欧美亚洲国产一区二区三区 | 精品人妻人人做人人爽 | 国产深夜福利视频在线 | 久久久中文字幕日本无吗 | 精品国产aⅴ无码一区二区 | 在线 国产 欧美 亚洲 天堂 | 高清国产亚洲精品自在久久 | 国产美女精品一区二区三区 | 国产69精品久久久久app下载 | 东京无码熟妇人妻av在线网址 | 无码乱肉视频免费大全合集 | 自拍偷自拍亚洲精品被多人伦好爽 | 天天拍夜夜添久久精品大 | 精品成人av一区二区三区 | 亚洲成在人网站无码天堂 | 国产精品毛多多水多 | 99久久亚洲精品无码毛片 | 中文字幕无线码 | 97精品人妻一区二区三区香蕉 | 图片小说视频一区二区 | 奇米影视7777久久精品人人爽 | 亚洲а∨天堂久久精品2021 | 欧美色就是色 | 精品国产aⅴ无码一区二区 | 欧美人妻一区二区三区 | 亚洲国产精品久久久久久 | 精品久久久久久人妻无码中文字幕 | 国产人妻精品午夜福利免费 | 欧美熟妇另类久久久久久不卡 | 亚洲精品久久久久avwww潮水 | 欧美乱妇无乱码大黄a片 | 久久人人爽人人爽人人片ⅴ | 国产真实伦对白全集 | 老熟女重囗味hdxx69 | 夜精品a片一区二区三区无码白浆 | 啦啦啦www在线观看免费视频 | 无人区乱码一区二区三区 | 麻豆果冻传媒2021精品传媒一区下载 | 在线播放无码字幕亚洲 |