【已轉移】【Java架構:基礎技術】一篇文章搞掂:Java 8

本文篇幅較長,建議合理利用右上角目錄進行查看(若是沒有目錄請刷新)。html

1、Java的歷史與演變 

目的:爲徹底瞭解Java,須要理解Java的誕生緣由、成型動力以及他繼承的思想。java

計算機語言的創新與發展的緣由:適應環境和用途的變化;實現編程藝術的完善和提升。程序員

1.一、Java的家世

Java大量特性從C和C++繼承過來。web

C語言的誕生

C語言前,BASIC、COBOL、FORTRAN這幾種編程語言沒有遵循結構化原則設計,依賴GOTO做爲程序控制手段;Pascal雖是結構化語言,但不是針對高效率設計的,沒法設計系統級代碼。正則表達式

C語言出現的2個條件:軟件需求加快,學術界在努力建立一種新的設計語言;計算機硬件普及,計算機再也不被鎖起來,程序員能夠隨意使用計算機進行嘗試。算法

C語言是一種功能強大、高效率、結構化的語言;並且他是程序員設計的,爲程序員服務的語言。數據庫

C++

出現的緣由:更好地管理程序的複雜性。編程

改進:C++是在C#的基礎上,增長了對面向對象(OOP)的支持,使程序員能理解和管理更大的程序。小程序

Java出現的條件

20世紀80年代末90年代初,萬維網(World Wide Web)和因特網發展到了臨界規模。設計模式

1.二、Java誕生

Java於1991年,由Sun公司構想出。

最初開發Java的推進力:對平臺獨立的語言的需求。

推進力

當時須要爲一些電子設備(微波爐、遙控器等)的各類CPU開發程序,若是使用C或者C++須要對每一種CPU開發對應的編譯器,因此須要一種可移植對平臺獨立的語言。

因特網成就Java:恰好這個時候因特網的飛速發展,也須要可移植的程序,Java的特性也適合於因特網的需求,使Java的關注點從消費電子產品轉移到Internet。

Java的特性

一、爲了吸引C/C++的程序員,Java繼承了不少C/C++的特性,但Java不是爲了替代它們,而是爲了解決特定領域問題而出現的。

二、Java是專門針對程序員的語言,由於他的設計、測試、改進都是由程序員完成,紮根與程序員的需求,也爲程序員開放了足夠的權限。

與C#的關係

Java影響了C#語言的發展,二者共享相同語法,支持分佈式編程,使用類似的對象模型。

1.三、Java改變Internet的方式

Internet推進了Java,Java也影響了Internet。

Java簡化了Web編程,建立了新的網絡程序類型applet,解決了一些Internet棘手問題如移植性和安全性。

Java applet

applet是一種能夠在Internet上傳送的程序,能夠在兼容Java的Web瀏覽器中自動運行。

applet擴展了網絡空間自由流動的對象的範疇。這是一種動態的,自動運行的代碼,由服務器端初始化,而後在客戶端自動運行。

雖然這種動態的聯網程序符合人們願望,可是同時帶來了嚴重的安全性和可移植性。

安全性

當下載這個自動執行的程序的時候,裏面可能包含各類病毒或者惡意代碼。

而Java將applet限定在Java的執行環境內,不容許訪問計算機的其它部分來實現安全性。

可移植性

applet會被下載到不一樣的環境,不一樣的系統中,如何實如今這些不一樣的環境下的運行,下面將講解。

1.四、Java的魔力:字節碼

解決安全性和可移植性的關鍵:字節碼。

Java編譯器輸出的不是可執行代碼,而是高度優化的指令集合。

字節碼在Java運行時系統中執行,Java運行時系統也稱爲Java虛擬機(Java Virtual Machine,JVM),原始也稱爲字節碼解釋器。

字節碼和JVM實現了移植性和安全性

  • 移植性:同一個程序,Java編譯器輸出的是相同的字節碼;而這個字節碼須要在不一樣的環境中運行,只須要實現對應環境的JVM便可;這些不一樣的JVM,運行的是相同的字節碼,從而實現了移植性。
  • 安全性:由於Java程序依賴JVM來運行,因此在JVM以外的系統其它部分,Java代碼是沒法修改的,從而實現了必定的安全性。
  • 速度:通常來講,這樣通過一箇中間層再執行代碼,理論上會慢一點;可是Java對字節碼進行了足夠的高度的優化,因此這個速度是足夠快的。
  • 執行代碼:爲了提升性能,Java也提供了HotSpot技術,爲字節碼提供了即時(Just In Time,JIT)編譯器,可將字節碼實時編譯爲系統可執行代碼。

1.五、servlet:服務器端的Java

Java橫跨服務器/客戶端:servlet是在服務器中執行的Java程序,像applet擴展了Web瀏覽器的功能同樣,servlet擴展了Web服務器的功能。

servlet用於動態建立發送到客戶端的內容,如servlet能夠讀取服務器數據庫,而後整理爲客戶端想要的內容,發送到客戶端;同時,servlet還提供了一些額外的優勢,例如性能的提高。

可移植性:由於servlet是Java程序,他們被編譯成字節碼,由JVM執行,因此servlet能夠用於不一樣服務器環境,只要服務器支持JVM和servlet容器。

1.六、Java關鍵特性

  • 簡單性:繼承C/C++語法和麪向對象特性;原本的設計目標就是讓程序員高效學習和使用。
  • 安全性:上面已講述。
  • 可移植性:上面已講述。
  • 面向對象:Java中的對象模型既簡單又容易擴展,基本類型仍然是高性能的非對象類型。
  • 健壯性:編譯時檢查代碼;可預見的方式運行;自動管理內存回收;面向對象的異常處理。
  • 多線程:Java提供了易用的多線程方法。
  • 體系結構中立:Java提供了Java虛擬機(JVM),解決了程序對不一樣電腦,或者同一臺電腦,不一樣狀態,可能致使程序不能運行的問題。
  • 解釋執行和高性能:雖然Java使用了字節碼和JVM,可是通過Java的優化,使用計時編譯器,可以使這種模式依然保持瞭如本機代碼同樣的高性能。
  • 分佈式:Java是針對Internet的分佈式環境而設計的,因此對分佈式有不少強大的支持。
  • 動態性:支持運行時類型信息,可在運行時驗證和解決對象訪問的問題。

2、Java綜述 

2.一、面向對象編程

面向對象編程(Object-Oriented Programming,OOP)在Java中處於核心地位。

兩種範式

全部計算機程序都包含2個元素:代碼、數據

  • 面向過程模型:將程序描述爲一系列步驟,並用代碼描述每個步驟將如何做用於數據。
  • 面向對象編程:將數據設計爲一系列對象,併爲這些對象精心設計接口,使用這些接口來進行組織代碼。

抽象

使用抽象管理複雜性:非面向對象的編程方式,每每將對象分解爲不一樣的部分進行處理;而面向對象的編程方式,則是把對象做爲一個總體,去使用這個對象。

層次化分類:如一臺車,下面又能夠分爲駕駛系統、制動系統等,每層又能夠繼續細分。當咱們去使用這個車的對象時,則只須要了解各系統如何操做,而不須要知道這個系統裏面由什麼組成

對變化的支持:面向對象的方式猶如人類理解事物同樣;每每事物會不斷變化,例如某一部分進行改變;那麼面向對象的程序也能支持這些變化,能夠優美地廢除或者替換舊系統中的一些部分。

2.二、OOP三原則

封裝

封裝:將代碼以及其操做的數據綁定在一齊的機制。能夠想象爲一個保護性的盒子,只容許外部經過盒子提供的通道進行訪問和操做,而不容許隨意訪問盒子裏面的代碼和數據。

封裝的基礎是類:類,是一些對象共享的一種結構和行爲(數據和代碼)。使用類建立對象,相似使用模具生產零件,這些對象也稱爲類的實例。

變量和方法:類裏面能夠定義變量和方法,稱爲成員變量(或實例變量)和成員方法(或方法)。

公有/私有:類的變量或方法能夠設置爲公有或私有,公有的表示外部用戶能夠知道的內容,私有的表示只有類的成員才能訪問。

繼承

繼承:是一個對象得到另外一個對象的屬性的過程,繼承支持了層次化分類的概念。

例如定義了一個哺乳類動物,又定義了下一層的一個類叫犬類,咱們定義犬類繼承了哺乳類,那麼就表明犬類有哺乳類的全部屬性和特徵(變量和方法)。

多態

多態(多種形態):容許將一個接口用於一類通用動做。

多態是爲了下降複雜性。例如一個對象有同一個行爲,可是根據數據不一樣有不一樣作法的時候,使用相同的接口來指定這個行爲,而自動根據對應的參數,會執行對應的實際代碼。

封裝、繼承與多態協同工做

經過這3個原則,能夠設計出健壯性強、方便維護、適應變化的系統級代碼。

下面例子應在安裝並配置好JDK 8下使用

2.三、Java基本語法

源文件

Java中源文件的正確名稱叫編譯單元(compilation unit),是一個包含一個或多個類定義(及其它內容)的文本文件。

要求源文件使用.java做爲擴展名;文件內主類的名稱與源文件名必須相同且大小一致。

代碼例子Test.java

class Test{
  public static void main(String args[]){
    System.out.println("測試");
  }
}

編譯成字節碼

在命令行中,執行命令,javac編譯器會建立名爲Test.class文件,這個就是字節碼文件

c:\>javac Test.java

運行程序

c:\>java Test

運行後,會顯示「測試」,表明程序運行成功

main()方法

Java會找到程序多個類中的main()方法啓動程序,注意大小寫,沒有找到會報錯

聲明變量

int num;

控制語句

if(num < 100)System.out.println("yes");

代碼塊

用{}表示邏輯單元

if(num<100){
  System.out.println("yes1");
  System.out.println("yes2");
}

詞彙問題

  • 空白符:能夠用空格、製表符或換行符隨意進行縮進。
  • 標識符:用於命名類、變量以及方法等。可由大小寫字母、數字、下劃線、美圓符號等字符組成的任意字符序列。不能以數字開頭,不建議使用下劃線。
  • 字面值:表示常量,如100,85.2,'X',"Long Text"
  • 註釋:Java有3種註釋
  • 分隔符:

  • 關鍵字:

3、數據類型、變量和數組

Java是強類型語言

在編譯器完成編譯前,會檢查全部表達式和參數,確保類型是兼容的。

基本類型(也稱簡單類型)

Java定義了8中基本數據類型

整型:byte、short、int、long,表示有符號整數。

通常使用int,不夠長度使用long

若是表達式中有byte、short類型,對錶達式求值時他們會被提高爲int類型

浮點型:float、double,表示帶小數位數字。

float:32位單精度數值,某些處理器上單精度運算速度更快,佔用空間是雙精度的一半,可是數值很大或很小時會變得不許確;在須要小數部分,可是精度要求不高的時候,建議使用float類型。

double:64位雙精度數值,在針對高速數學運算優化的現代處理器中,雙精度數值速度更快;在須要屢次迭代運算中保持精度,或者操做很是大的數值時,建議使用double類型。

字符型:char,表示字符集中的符號,好比字母和數字。

Java使用Unicode表示字符,Unicode是一個徹底國際化的字符集,能夠表示所有人類語言中的全部字符;Unicode是16位寬的,對好比ASCII字符集等更寬,效率有必定程度下降,這是Java爲了全球化而作出的一點犧牲。

布爾型:boolean,表示true/false值的特殊類型。

深刻分析字面值

整型字面值

int x=06;//0開頭表示8進制
int x=0x2f;//0x或0X開頭表示十六進制
int x=0b1010;//0b或0B開頭表示二進制
int x=123_456_789;
int x=123___456___789;//可在數值中嵌入一個或多個下劃線,方便觀看,編譯時會去掉

浮點型字面值

float num = 2.44F;//默認浮點數爲雙精度,後面加F或f標明單精度
double num = 2.44D;//雙精度能夠這樣表示,可是默認就是雙精度,因此多餘
double num = 3.13148;//標準計數法
double num = 2E-5;//科學計數法,能夠用E或e後+正負號(正可省略)+十進制來表示
double num = 3_432_442.0_2_2;//同樣能夠用下劃線分割

布爾型字面值

  Java中只能用true和false,不能用1或0

字符型字面值

char t = 'a';//用單引號表示字符
char t = '\141';//八進制表示子母a
char t = '\u0061';//十六進制表示Unicode字符a
char t = '\n';//轉義字符表示換行符

字符串字面值

字符串中一樣能夠使用轉義字符以及八進制/十六進制表示方法

Java中字符串開頭和結尾必須同一行,沒有分行輸入的功能

其它語言中字符串是字符的一個數組,而Java中是把字符串做爲一個對象(因此不能用a==b來判斷2個字符串,由於2個對象是不一樣的)

"Hello World"//使用雙引號表示

變量

類型開始,能夠連續定義多個變量,初始值可選

int a,b,c;
int a=1,b,c=1;//連續定義3個int類型變量,其中2個加入初始值
int a=1;//使用常量初始化
doucle c=Math.sqrt(a*a+b*b);//使用公式初始化

變量做用域:

花括號{}表示代碼塊,變量的做用域在其所在的代碼塊中,離開代碼塊,變量會丟失他的值

類型轉換和強制類型轉換:

自動類型轉換:當把一個類型的數據賦值給另一個類型的變量時,若是知足條件,會發生自動類型轉換。

條件:兩種類型兼容;目標類型大於源類型。

知足上述條件,會發生擴寬轉換。

例如把byte值賦值給int類型變量

強制類型轉換

int a;  
byte b = (byte)a;//縮小轉換
double c;
int d = (int)c;//浮點數轉爲整型,會把尾數直接截掉,而且若是整數部分太大,會轉換爲整數部分除以目標類型範圍的餘數,例如轉換爲byte類型,就是除以256

自動類型提高

原則:
一、表達式中的byte、short、char值都會提高爲int
二、若是其中一個操做數爲long,整個表達式會提高爲long
三、若是其中一個操做數爲float,整個表達式會提高爲float
四、若是其中一個操做數爲double,整個表達式會提高爲double

byte b=50;
b=b*2;//錯誤,由於進行了自動提高,b在表達式中變成了int類型,因此b*2的結果是int類型,賦值給更小的類型byte會報錯
b=(byte)b*2;//正確

數組

int array1[];//建立數組變量,只是變量,未分配內存
array1 = new int[12];//元素自動初始化爲0(數值類型)、false、null(引用類型)
array1[3]=28;//使用[索引]進行訪問
System.out.println(array1[3]);
int array1[] = new int[12];//結合起來的寫法
int array1[] = {1,2,3,4,5};//初始化式聲明

//多維數組
int twoD[][] = new int[4][5];//多維數組
//不一樣長度的多維數組
int twoD[][] = new int[4][];
twoD[0] = new int[1];
twoD[1] = new int[2];
twoD[2] = new int[3];
twoD[3] = new int[4];
//初始化寫法
double m[][] = {
    { 1, 2 }, 
    { 3, 4 }, 
};

//另一種寫法
int a1[] = new int[3];
int[] a1 = new int[3];
char twod1[][] = new char[3][4];
char[][] towd1 = new char[3][4];
int[] a1,a2,a3;
int a1[],a2[],a3[];

關於字符串的說明

在Java中,字符串類型是String

可是String不是一個基本類型,而是一個對象,爲他提供了一些面向對象的特性,因此放在後面探討

關於指針

由於Java使用了JVM,限定了Java程序的執行邊界,Java程序不容許使用指針。

由於指針能夠訪問內存中任何地址,破壞了JVM和宿主計算機之間的防火牆,和Java的設計理念不一樣,因此Java不容許使用。

5、運算符

算數運算符

基本算數運算符+ - * /
注意整數類型使用除法,結果會截掉小數部分

求模運算符%
求餘數,能夠用於整數或小數

算數與賦值符合運算符+= -= *= /=
至關於運算後再賦值

自增與自減運算符++ --

y=x++;//先將x原值賦值給y,而後x加1
y=++x;//x先加1,而後將x加1後的值賦值給y

位運算符

位操做較少用,這裏略過

關係運算符

布爾邏輯運算符

賦值運算符

a=1;//使用"="符號賦值
a=b=c=100;//將3個變量都賦值爲100

「?」運算符

a=b==0?true:false;//用於簡寫的判斷

優先級

使用圓括號

圓括號能夠提高運算的優先級,而且能使閱讀更加明確易懂,又不影響性能。

a=(b==0?true:false);

5、控制語句

選擇語句

if語句
if(a=1){
  b=1;
}
else if(a=2){
  b=2;
}
else{
  b=3;
}
switch語句
switch(a){
  case 1:
    b=1;
    break;
  case 2:
    b=2;
    break;
  case 3:
  case 4:
    b=3.5;
    break;
  default:
    b=100;
    break;
} 

迭代語句

while
while(n>0){
  System.out.println(n);
  n--;
}
i=100;
j=200;
while(++i<--j);//用;表示空語句
do-while

循環體至少執行一次

do{
  System.out.println(n);
  n--;
}while(n>0)
for
int n;
for(n=10;n>0;n--){
  System.out.println(n);
}
for(int n=10;n>0;n--){
  System.out.println(n);
}
for(a=1,b=4;a<b;a++,b--){
  System.out.println(a);
  System.out.println(b);
}
for-each

for-each風格在不一樣的編程語言中都有實現,是一種很受程序員喜歡的風格
在Java中,是經過for語句實現的,能夠對集合類變量進行循環

int nums[] = {1,2,3,4,5}
int sum = 0;
for(int x:nums){
  sum+=x;
}

跳轉語句

break

用於終止當前所在的最近一個循環

for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m==5)break;//跳出m的循環
  }
}
break label

能夠使用標籤,終止語句所在的全部嵌套循環中的其中一個

outer:for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m==5)break outer;//跳出n的循環
  }
}
continue

提早終止循環的一次迭代
在本次迭代中,在continue後面的代碼將不會執行

for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m>5)continue;//跳出m的一次迭代
  }
}
continue label

能夠使用標籤,終止語句所在的全部嵌套迭代中的其中一個

outer:for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m>5)continue outer;//跳出n的一次迭代
  }
}
return

顯式地從方法返回,把程序的執行控制返回到發放的調用者處

6、類

類的形式

//類的基本形式
class Box{
  double width;//實例變量
  double height;//實例變量
  double depth;//實例變量

  //無參構造函數,new Box()實際是調用了類的構造函數
  Box(){
    width = 10;height= 10;depth= 10;
  }
  //帶參構造函數
  Box(double width,double height,double depth){
    this.width = width;//使用this引用實例對象
    this.height= height;
    this.depth= depth;
  }

  double volume()//方法,返回值、參數都是可選的
  {
    return width * height * depth;
  }
}

//建立類的實例
Box mybox1;//聲明一個Box類型變量
mybox1 = new Box();//建立一個實際對象,並將引用到上面的變量中
Box mybox1 = new Box();//簡寫方式
mybox.width = 100;//爲實例變量賦值

//變量引用的概念
Box b1 = new Box();
Box b2 = b1;
b1 = null;
//此時b2不是null,而是引用第一行建立的對象
//由於第二行代碼是把b1引用的對象也給b2引用
//第三行代碼,只是將b1的引用去除,並不影響b2和對象的引用

垃圾回收

當對象用完後,應該把對象在內存中清掉,釋放內存。
這方面Java會自動管理,大多數狀況不須要人爲編程。

finalize()方法

爲類添加這個方法,能夠在類的對象被Java回收的時候執行方法內的代碼。

protected void finalize()
{
  //記錄回收時間等自定義方法
}

7、方法和類深刻分析

重載方法

Java中支持多態性的方式之一
支持多個不一樣參數的方法共享方法名稱,經過傳入的參數來判斷調用哪一個具體方法

class OverloadDemo{
  void test(){
  System.out.println("test1");
  }
  void test(int a){
  System.out.println("test2");
  }
  void test(int a,int b){
  System.out.println("test3");
  }
}
class Overload{
  public static void main(String args[]){
    OverLoadDemo ob = new OverloadDemo();
    ob.test();//調用無參的方法
    ob.test(10);//調用1個int參數的方法
    ob.test(10,20);//調用2個int參數的方法
  }  
}

對象能夠做爲參數

能夠將對象做爲參數傳遞給方法

參數的傳遞

  • 傳遞的形式分爲:值傳遞,引用傳遞
  • 基本類型的參數,使用的是值傳遞
  • 其它類型的參數,使用的是引用傳遞
  • 參數使用值傳遞,至關於建立該值的一個副本,修改該參數,不會影響原值
  • 參數使用引用傳遞,至關於把參數指向和原值所指向的同一個對象,因此修改參數值的時候,其實是在修改其所指向的對象,因此原值也會一齊變化。

對象能夠做爲返回值

能夠講對象做爲參數的返回值返回

遞歸算法

方法能夠調用本身實現遞歸算法

訪問控制

  • 爲了使類能夠更好地封裝,咱們系統能夠把類看成一個黑盒子,只對外暴露能夠訪問的成員
  • Java提供了訪問修飾符來實現這種封裝
  • public:成員被public修飾,能夠被任何代碼訪問,無修飾符時默認爲public
  • private:成員被private修飾,該成員只能被所屬類的其它成員訪問
  • protected:涉及繼承纔會使用下章介紹

static

用於聲明類自己的成員,而不是對象的成員
限制:
一、只能直接調用其它靜態方法
二、只能直接訪問靜態數據
三、不能引用this或super關鍵字

class UseStatic (
  static int a * 3;//靜態變量
  static int b;//靜態變量

  static void meth(int x) {//靜態方法
    System.out.println("x:" + x);
    System.out.println("a:" + a);
    System.out.println("b:" + b);

  static (//靜態代碼塊,會在加載此類時運行,整個程序生命週期僅運行一次
    System.out.println("Static block initialized");
    b = a * 4;
  }

  public static void main (String args[]) {
    meth(42);//調用靜態方法
  }
 }

靜態方法、靜態變量也能夠看做是Java中的全局方法和全局變量

final

能夠用於聲明變量或者方法

//聲明變量,能夠將變量定義成常量
//表明整個程序生命週期,他的值不能改變
//約定寫法爲全大寫
final int FILE_NEW = 1;

final聲明方法與聲明變量的用法有本質區別,下章討論final聲明方法的用法

從新審視數組

數組的length成員
只反映最初設計時數組所能包含的元素數量

int a1[] = new int[10];
System.out.println("length is " + a1.length);

嵌套類和內部類

嵌套類:在一個類的內部再定義一個類,這個再定義的類稱爲嵌套類;外部的類稱爲包含類

限制:

  • 一、嵌套類不能獨立於包含類存在
  • 二、嵌套類能夠訪問包含類的成員(含私有成員)
  • 三、包含類不能訪問嵌套類的成員
  • 四、嵌套類能夠做爲包含類的成員聲明;也能夠在代碼塊中聲明

嵌套類按是否靜態能夠分爲2種:靜態的、非靜態的

由於靜態嵌套類只能訪問包含類的靜態成員,只能經過對象訪問包含類的非靜態成員,因此不多這樣使用

非靜態的嵌套類稱爲【內部類】

class outer
  int outer_x = 100;
  void test(){
    Inner inner = new Inner();
    inner.display();
  }

  //內部類
  class Inner{
    void display{
      System.out.println("display: outer_x ="+ outer_x);
    }
  }

  //代碼塊中定義內部類
  void test2(){
    for(int i=0;i<10;i++){
      class Inner2{
        void display(){
          System.out.println("display:outer_x = " + outer_x);
        }
      }
      Inner inner = new Inner();
      inner.display();
    }
  }
}
class InnerClassDemo{
  public static void main(String args[])(
    Outer outer new Outer();
    outer test();
  }
}

String類介紹

Java中每一個字符串,包括變量和常量,都是一個String對象

//多種方式構造字符串
String myString = "this is a test";

//引用
System.out.println(mySting);

//Java爲String對象定義了「+」運算符
String myString1 = "I" + " Love You";

//經常使用方法
//equals方法判斷相等
if(str1.equals(str2))
  System.out.println("equals");
//length方法獲取長度
if(str1.length()==0)
  System.out.println("空字符串");
//charAt方法獲取字符
System.out.println("equals".charAt(0));

//常見錯誤,2個相同字符串是不相等的,由於是2個對象
if("yes"=="yes")
  System.out.println("Yes");

varargs:可變長度參數

限制:
一、一個方法最多隻有一個可變長度參數
二、可變長度參數必須放到最後

class VarArgs{
  static void vaTest(int ... v){
    for(int x : v){
      System.out.println(x);
    }
  }
}

8、繼承

一個類能夠繼承另一個類,被繼承的類叫超類,繼承別人的類叫子類

extends

繼承:

  • 一、子類包含了超類的全部非私有成員
  • 二、一個類只能有一個超類
class A{
  int i = 1;
  void showi(){
    System.out.println("i = "+i);
  }
}
class B extends A{
  int j = 2;
  void showj(){
    System.out.println("j = "+i);
  }
}

超類變量引用子類對象

變量的成員決定於變量類型,而不是對象類型

class test(){
  void test(){
      A a = new B();
  }
}

super關鍵字

用法1:子類構造函數中調用超類構造函數

class B extends A{
    B(){
        super();//調用超類A的構造函數
    }
}

用法2:引用超類被子類隱藏的成員

class A{
  public string name = "a";
  void showA(){
    System.out.println(name);
  }
}
class B extends A{
  public string name = "b";//同名成員,隱藏了超類的name成員
  void showB(){
    System.out.println(name);//b
    System.out.println(super.name);//a
  }
}

多級繼承層次

類能夠無限級繼承

構造函數的執行順序

從最上層超類的構造函數到最下層子類的構造函數執行

重寫(隱藏)

當子類的成員與超類成員名稱相同且參數類型相同,會把超類成員重寫(隱藏),可是能夠經過super調用超類的成員

動態方法調度

Java經過對象的類型選擇調用的成員,而不是變量的類型

class A{
  void call(){
    System.out.println("a");
  }
}
class B{
  void call(){
    System.out.println("b");
  }
}
class C{
  void call(){
    System.out.println("c");
  }
}
class Test{
  public static void main(String args[]){
    A a = new A();
    A b = new B();
    A c = new C();
    a.call();//輸出a
    b.call();//輸出b
    c.call();//輸出c
  }
}

抽象類

使用abstract類型修飾符修飾的類

  • 一、抽象類不存在對象,不能用new實例化。
  • 二、不能聲明抽象的構造函數。
  • 三、不能聲明抽象的靜態方法。
  • 四、子類要麼實現全部抽象方法,要麼本身聲明爲抽象的。
  • 五、應用動態方法調用,抽象類能夠做爲變量引用,引用其子類所建立的對象,調用其抽象方法時,實際是調用對應對象所實現的方法。

繼承中使用final關鍵字

一、可以使用final關鍵字阻止重寫
二、可以使用final關鍵字修飾類,防止類繼承

Object類

Object類是全部其它類的超類
Object類型的引用變量能夠應用其它全部類
Object類型能夠引用數組,由於數組也是做爲類來實現的
因此全部對象均可以使用Object的方法

9、包和接口

若是全部類都放一塊兒開發,方便易記的類名很快用完,也很容易出現協做時命名衝突的問題。
包是Java提供的一種命名機制,同時也是一種可見性控制機制。

包定義

Java使用文件系統目錄存儲包,包名必須和目錄路徑一致,包括大小寫

//定義包名,寫在Java源文件中的第一條語句
package pkg;

//層次化
package java.awt.img;
包查找與CLASSPATH

Java運行時怎麼找到這些包呢?

package MyPack;

3種方式:

  • 一、Java程序運行目錄下有MyPack目錄
  • 二、CLASSPATH環境變量下有Mypack目錄
  • 三、運行程序時經過-classpath選項指明包路徑運行

類成員的訪問保護

而對【非嵌套類】只有2種訪問級別

  • 默認級別:只能被同包中的其它類訪問。
  • 公有級別:任何其它代碼均可訪問;要求該類是文件中惟一一個公有類,切文件名要和類名徹底一致。

導入包

import java.util.Data;
import java.io.*;//導入整個包

Java隱式地爲全部代碼都導入了java.lang包,至關於每一個源文件開頭都添加了

import java.lang.*;

import語句是可選的,也能夠選擇使用徹底限定名來使用類

class MyDate extends java.util.Date{
}

接口

使用interfere建立接口,可用於指定類必須實現哪些功能

定義接口

interface Callback{
  void callback(int param);
}
  • 一、若是接口沒有修飾符,採用默認訪問級別,只有聲明接口的包中的其它成員才能訪問接口。
  • 二、若是接口聲明爲public,那麼全部代碼均可以使用接口,且接口是當前文件中的惟一公有接口,文件名必須和接口同名。
  • 三、JDK 8及之後的版本中,能夠爲接口建立默認實現。
  • 四、接口中能夠聲明變量,隱式標識爲final和static,全部實現接口的類都不能修改他們,還必須初始化他們。
  • 五、全部方法和變量都隱式聲明爲public。

實現接口

class Client implements Callback{
  public void callback(int p){
    System.out.println(p);
  }
}
  • 一、實現接口方法時,必須聲明爲public
  • 二、使用接口調用方法,是在運行時動態查詢到方法並執行,和常規方法調用相比佔用更多資源,對性能要求苛刻的代碼中謹慎使用。
class TestIface{
  public static void main(String args[]){
    //使用接口調用方法
    Callback c = new Client();
    //調用的方法是來自對象,而不是類型變量
    c.callback(42);
  }
}
  • 部分實現:
  • 若是類實現一個接口,可是沒有實現全部接口方法,那麼必須將這個類聲明爲abstract
abstract class Incomplete implements Callback{
  void show(){
    System.out.println("Good");
  }
}

接口中的變量

建立一個包含變量的接口,實現這個接口的類至關於把這些這些變量看成常量導入到類的命名控件下。

interface SharedConstants{
  int NO = 0;
  int YES = 1;
  int NULL = 2;
}

這種用法有爭議,僅做介紹

接口的繼承

接口能夠繼承,實現一個子接口,必須實現這個接口的繼承鏈上全部接口的全部方法。

默認接口方法default

【JDK8】纔出現

默認方法也稱擴展方法

能夠爲接口的方法提供默認實現

動機:

  • 一、當接口須要增長一個方法,那麼實現接口的類必須實現這個方法,致使增長方法會破壞原有代碼;
  • 二、提供可選方法。例若有一個接口有一個方法remove,有2個類都實現了這個接口,其中一個類但願他是不可刪除的,原來方法就須要寫一個remove的空實現。如今有了默認方法,能夠在接口默認空實現,或拋出異常,這樣類就不用去作空實現了。
public interface MyIF{
  //使用default關鍵字
  default String getString(){
    return "Default";
  }
}

優勢:

  • 一、優雅地隨時間演進接口
  • 二、提供可選功能,且類沒必要在不須要該功能時提供佔位符實現。

不一樣接口的同名方法

一個類實現了2個接口,2個接口都有默認方法reset,那麼使用方法的順序以下:

  • 一、類有實現,優先類的實現
  • 二、類沒有重寫實現,則報錯

若是是一個接口繼承另一個接口,且有相同默認方法,則繼承接口的版本更高優先級

//顯式調用被繼承接口中的默認實現
SuperInterface.super.reset();

在接口中使用靜態方法

【JDK 8】纔出現

能夠在接口中直接定義靜態方法,而後直接調用

public interface MyIF{
  static int getDefaultNumber(){
    return 0;
  }
}

//調用
int a = MyIF.getDefaultNumber();

注意:
一、實現接口的類或子接口不會繼承接口中的靜態方法。

10、異常處理

異常處理

處理程序運行時的非正常狀態,即運行時錯誤。
Java會在出現異常時,拋出一個異常對象。

異常類型

全部異常對象都是Throwable的子類

Exception:用於用戶程序應當捕獲的異常,或者自定義的異常

RuntimeException:程序自動定義

Error:通常指運行時環境出現的錯誤

未捕獲的異常

若是出現異常且未捕獲,程序會終止,並輸出堆棧信息,能夠根據堆棧信息幫助查找問題。

使用try和catch

程序處理異常,會終止程序。

咱們本身處理異常,一能夠修復錯誤,二能夠避免終止程序。

try{
  do();
}catch(Exception1 e){
  System.out.println(e);//輸出異常信息
  catchDo();
}catch(Exception2 e){//能夠多個catch語句
  catchDo();
}
  • 一、在try{}的代碼中,若是出現異常,則在代碼塊中異常代碼後面的代碼會跳過,直接轉到catch裏面
  • 二、能夠寫多個catch語句
  • 三、若是嵌套了try,若是內層try沒有處理異常,異常會拋出到外層的try裏面去。

throw

顯式拋出異常

throw ThrowableInstance;

這個異常必須是Throwable或其子類類型的對象。

throws

除了Error和RuntimeException及其子類類型的異常外,若是方法有其它類型的異常,則須要爲方法標明這些異常。

目的是讓方法的調用者知道此方法全部異常以作好準備措施。

public void do() throws MyException{
  throw new MyException("test");
}

finally

可選加載try{}catch{}後,不管是否拋出異常,都會在try{}catch{}後執行此代碼

try{
  do();
}catch(Exception1 e){
  System.out.println(e);//輸出異常信息
  catchDo();
}finally{
  finallyDo();
}

Java內置異常

未經檢查(編譯器不檢查這些異常是否使用throws標明)的RumtimeException子類

須要檢查的Java定義的異常類

建立本身的異常子類

一、定義Exception的子類便可

二、Exception沒有爲本身定義任何方法,可是繼承了Throwable提供的方法

三、Exception有4個公有構造函數,其中2個支持鏈式異常(下面介紹),另外2個以下

Exception()
Exception(String msg)

鏈式異常

當一個異常的拋出,是由於另一個異常致使的,但願能把這個異常鏈顯式出來,因此提出了鏈式異常。
Throwable中有2個構造函數和2個方法

//2個構造函數
Throwable(Throwable causeExc)
Throwable(String msg,Throwable causeExc)
//2個方法
Throwable getCuase()//返回引起當前異常的異常
Throwable initCause(Throwable causeExc)//建立異常後將背後異常和建立的異常聯繫在一塊兒,只能調用一次

一般initCause是用於不支持前面2個構造函數的遺留異常類設置緣由

JDK7開始添加的3個異常特性

一、帶資源的try語句

當try語句中使用資源時,再也不須要時資源能自動釋放(如文件),後面解釋

二、多重捕獲

容許同一個catch子句同時捕獲多個異常

catch(Exception1 | Exception2 e)

每一個多重捕獲參數都被隱式聲明爲final,不能從新賦值

三、最後從新拋出/更精確地從新拋出(不是很理解,暫時不理)

程序會對從新拋出的異常類型進行限制,只能從新拋出知足如下條件的經檢查的異常:由關聯的try代碼塊拋出,沒有被前面的catch子句處理過,而且是參數的子類型或超類型。

一樣catch參數隱式聲明爲final,不能從新賦值

11、多線程編程

多任務:

  • 基於進程:運行多個程序
  • 基於線程:單個程序同時運行多個任務

Java線程模型:

  • 單線程模型:輪詢時間循環:輪詢一個事件隊列,當執行一個事件並返回以前,不能執行其餘工做
  • 多線程模型:併發執行的線程共享CPU,每一個線程獲得一篇CPU時鐘週期。

線程的狀態:

  • 運行:只要得到CPU時間就準備運行
  • 掛起:臨時中止線程活動
  • 恢復:讓掛起的線程變成運行狀態
  • 阻塞:等待資源時,線程處於阻塞狀態
  • 終止:一旦終止不能恢復

線程優先級:

一些整數,用於決定什麼時候從一個運行的線程切換到下一個線程,稱爲上下文切換

意思應該是這樣,根據CPU時鐘週期,空餘時間能夠用來運行線程;當線程過多,而有線程阻塞時,何時切換到下一個進程呢:

  • 一、運行的線程資源放棄控制:顯式放棄控制權、休眠或I/O以前阻塞,則檢查全部線程,優先級最高的線程會得到CPU資源
  • 二、高優先級線程取代低優先級線程:只要高優先級線程但願運行,就會取代低優先級線程,稱爲搶佔式多任務處理
  • 三、相同優先級的2個線程競爭CPU,Windows系統下會循環獲取CPU資源,而其餘系統除非正在運行的線程放棄控制權,不然其餘線程不能運行(因爲不一樣系統不一樣,可能引發移植性問題)

同步:

  • 某個線程位於一個同步方法中,則其餘線程不能調用對象的其它同步方法

消息傳遞:

  • Java的消息傳遞系統容許某個線程進入對象的同步方法,而後進行等待,而後其它線程顯式通知這個線程退出爲止

Thread類和Runable接口:

Java的多線程系統基於Thread類、Thead類的方法以及伴隨接口Runable而構建

主線程:

Java啓動就會運行一個線程,稱爲主線程。

很重要:

  • 一、其它子線程都是由主線程產生
  • 二、一般主線程必須是最後才結束執行的線程,由於他要執行各類關閉動做。

調用主線程

  • Thread t = Thread.currentThread();//獲取主線程
  • t.setName("");//修改進程名字

建立線程

2種方法:

  • 一、實現Runable接口
  • 二、擴展Thread類自己

 

實現Runable接口

  • Runnable接口抽象了一個可執行代碼單元,能夠依託任何實現了Runnable接口的對象來建立線程。
  • 要實現Runnable接口,只須要實現run()方法,而後run()方法能夠調用其它方法,使用其它類,聲明變量,像main線程那樣,惟一的區別就是入口點不一樣,run()方法爲併發線程執行創建了入口點,run()方法返回時,這個線程也將結束。
  • 而後建立實現了Runnable接口的類後,能夠實例化一個Thread類型的對象,而後調用線程start()方法才真正線程。

擴展Thread類

一樣的,擴展Thread類,重寫run()方法,而後調用start()方法類開始新線程

 

爲何有2種方式,哪一種好?

差異不大,一個是在於實現接口,一個是擴展重寫類。

能夠使用接口,這樣能夠使這個類能夠擴展其它類。

 

建立多個線程

 

isAlive()和join()方法

好比主線程但願等全部子線程執行完成再退出

isAlive()判斷線程是否仍在運行

可是通常經過join方法來等待線程結束

再某個線程調用其它線程的join方法,會等待該線程終止。

也能夠配置最長等待時間。

 

線程優先級

一、影響線程獲得CPU時間的因素:優先級、系統多任務的方式等

在搶佔式多任務環境下,高優先級的線程會替代掉低優先級的線程

在非搶佔式多任務環境下,在運行中線程正常運行狀況下(未休眠,未放棄控制權等),其它線程只有在運行中線程阻塞狀態,如I/O等待等,致使線程掛起,纔有機會運行

因此爲了平滑多個線程的執行,最好常常釋放控制權,使其它線程有機會運行。

調用setPriority方法設置線程優先級,範圍1~10,默認值5

使用Java實現可預測,跨平臺行爲的最安全方法是使用資源放棄CPU控制權的線程。

 

同步

當多個線程須要訪問共享資源時,他們須要用某種方法確保每次只有1個線程使用資源。

實現這個目的的過程稱爲同步。

 同步使用監視器的概念實現,監視器做爲互斥鎖,一個時刻只有一個線程能夠進入監視器,而其餘試圖進入監視器的線程會被掛起,知道上一個線程退出監視器。

 

2種方法

 

使用同步方法:

Java中,全部對象都有和自身關聯的隱式監視器。要進入對象的監視器,只須要調用synchronized關鍵字修飾過的方法。

當調用對象的一個同步方法,線程就會進入對象的監視器;其它線程想要調用這個或其餘同步方法,因爲進入不了監視器,因此會被掛起等待;知道監視器種的線程退出,把對象的控制權交給下一個等待線程。

 

使用同步語句:

 

 

 

線程間通訊:

 

十3、I/O、applet以及其餘主題

13.一、I/O

I/O:輸入輸出

流:

  • Java程序經過流執行I/O。
  • 流是一種抽象,要麼產生信息,要麼使用信息。
  • 流經過Java的I/O系統鏈接到物理設備。
  • 全部流的行爲方式都是相同的,即便他們連接的物理設備不一樣。
  • 所以,能夠將不一樣類型的輸入(磁盤文件、鍵盤或網絡socket),抽象爲輸入流;輸出流也能夠引用控制檯、磁盤文件或網絡連接。

2種類型的流:

  • 字節流:負責處理字節的輸入和輸出。
  • 字符流:使用Unicode編碼,爲處理字符的輸入和輸出提供更方便的方法,某些狀況下比字節流高效。

通常原則:在合適的狀況下,應該更新代碼,使用字符流替代字節流。

不過:在底層,全部I/O最終仍是面向字節的。

字節流類

2個類層次:

  • 頂層:2個抽象類InputStream和OutputStream
  • 子類:用於處理不一樣設備的具體子類

InputStream和OutputStream最重要2個方法是read()和write(),子類須要實現這2個方法

字符流類

2個類層次:

  • 頂層:Reader、Writer,這2個抽象類處理Unicode字符流。
  • 子類:用於處理不一樣設備的具體子類

Reader和Writer最重要2個方法是read()和write(),子類須要實現這2個方法

預約義流:

  • Java預約義了3個流變量,在java.lang包的System類中,分別爲in、out、err,而且聲明爲pubilc、static、final,因此程序任何地方均可以使用他們。
  • System.out引用標準輸出流,默認控制檯。
  • SYstem.in引用標準的輸入流,默認鍵盤
  • System.err引用標準的錯誤留,看默認控制檯。
  • 可是能夠重定向到任何兼容I/O設備
  • System.in是InputStream類型對象;out和err是PrintStream類型對象;都是字節流。
import java.io.*;

public class test {
    public static void main(String[] args) throws IOException {
        // 使用InputStreamReader將字節輸入流InputStream轉換成字符輸入流Reader
        // 使用BufferedReader讀取緩衝的輸入流

        // 讀取字符
        {
            char c;
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("輸入字符,q退出");
            do {
                c = (char) br.read();// 讀取字符
                System.out.println(c);
            } while (c != 'q');
        }

        // 讀取字符串
        {
            String str;
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("輸入字符串,stop退出");
            do {
                str = br.readLine();// 讀取字符串
                System.out.println(str);
            } while (!str.equals("stop"));
        }

        // 輸出
        {
            // System.out類型是PrintStream類,派生自OutputStream,提供了print和println方法,同時也實現了write
            System.out.print("A");
            System.out.print("\n");
            System.out.println("B");
            System.out.write('C');
            System.out.write('\n');
        }

        // 推薦使用字符流的輸出方法,更容易國際化
        // 使用PrintWriter
        {
            PrintWriter pw = new PrintWriter(System.out, true);
            pw.println("long text");
            int i = 1;
            pw.println(i);
            double d = 4.5e-7;
            pw.println(d);// 4.5E-7
            double d2 = 0.000000045;
            pw.println(d2);// 4.5E-8
        }
    }
}

 文件I/O(暫略)

主要是FileInputStream、FileOutputStream、AutoCloseable接口

13.二、applet(暫略)

一種Java程序,能夠在Internet服務器上訪問,傳輸,自動安裝並做爲Web文件的一部分運行的一類小程序。

13.三、幾個主題

transient修飾符:

  • 用來修飾類的變量,那麼該類的對象寫入永久存儲區域時,不會保存該屬性的內容

volatile修飾符:

  • 用來修飾類的變量,標明實例變量能夠被程序的其它部分隨意修改。
  • 例如在多線程下,正常一個變量在一個線程中是有一個副本,而後經過同步方法來工做,可是這種有效效率並不高。
  • 能夠用這個修飾類變量,使其主副本和其它私有版本保持一致,各個線程訪問主變量的順序與全部私有副本相同。

instanceof:

  • 判斷對象是否該類型或是否能夠轉換爲該類型。

strictfp:

  • Java2對浮點計算模型放寬了,不須要截斷特定的中間值,能夠防止溢出。
  • 而使用strictfp修飾類、方法、接口,能夠使用舊版本Java的浮點計算方式。

native:

  • 本地方法,能夠從Java內部調用非Java語言編寫的子例程。

assert:

  • 斷言,經過則不執行,不經過則拋出異常。2種形式。運行時默認禁用斷言,能夠運行時給予參數啓用或禁用斷言。

import static:

  • 靜態導入,導入靜態成員,節省代碼。

this():

  • 調用重載的構造函數,避免在重載的構造函數中代碼重複。使用this(),能夠減小重複代碼,減小了對象代碼,提升了對象的加載時間;可是this()的調用和返回又會下降代碼執行速度。
  • 若是類只建立少許對象,或調用this()構造函數不多調用,那麼沒有問題;可是若是須要建立數千個對象或常常調用this函數,這個必須衡量加載時間和執行速度。
  • 2個限制應該牢記:調用this()時不能使用當前類任何實例變量;同一個構造函數不能同時使用super()和this(),由於她們必須是構造函數中的第一條語句

緊湊API配置文件:

  • conpact一、compact二、compact3;2包含1,3包含2;可配置每一個配置文件中包含的庫,減小庫的大小,減少加載時間。

十4、泛型

目的:爲了解決不一樣類型的對象須要運行同一算法的需求

泛型:參數化類型,能夠使用參數指定所操做數據的類型

之前:要實現這個需求,則使用Object來引用,由於Object是其它全部類的超類,可是不能以類型安全的方式進行工做。

如今:泛型提供了類型安全性,也避免了顯式強制類型轉換,更安全、容易地重用代碼。

泛型類:

import org.junit.Test;

public class test {
    class Gen<T> {
        T ob;
        Gen(T o) {
            ob = o;
        }
        T getob() {
            return ob;
        }
        void showType() {
            System.out.println("Type of T is" + ob.getClass().getName());
        }
    }

    @Test
    public void test() {
        Gen<Integer> iOb;
        iOb = new Gen<Integer>(88);
        iOb.showType();
        int v = iOb.getob();
        System.out.println("value:" + v);

        System.out.println();

        Gen<String> strOb;
        strOb = new Gen<String>("Test");
        strOb.showType();
        String str = strOb.getob();
        System.out.println("value:" + str);
    }
}

泛型只能使用引用類型,不能使用基本類型

多個參數的泛型類,差很少,Gen<T,V>

有界類型:

限制參數類型的範圍,使用extends和&鏈接符,能夠使用類和接口限定

class Gen<T extends MyClass & MyInterface>{
}

通配符參數:

當其餘類須要引用泛型類,能夠不寫參數,或者使用通配符參數;通配符參數還能夠使用有界通配符(包括extends上界和super下界)

public class test {
    class Gen<T> {
        T ob;
        Gen(T o) {ob = o;}
        T getob() {return ob;}
        void showType() {
            System.out.println("Type of T is" + ob.getClass().getName());
        }
    }
    class Gen1 {
        public void m1(Gen g){// 直接引用類名
            g.showType();
        }
    }
    class Gen2 {
        public void m1(Gen<? extends Integer> g){// 要求泛型的類型是Integer或Integer的子類
            g.showType();
        }
    }
    class Gen3 {
        public void m1(Gen<? super Integer> g){// 要求泛型的類型是Integer或Integer的超類
            g.showType();
        }
    }
    @Test
    public void test() {
        Gen<Integer> iOb;
        iOb = new Gen<Integer>(88);
        iOb.showType();
        int v = iOb.getob();

        new Gen1().m1(iOb);
        new Gen2().m1(iOb);
        new Gen3().m1(iOb);
    }
}

泛型方法:

public class test {
    // 泛型方法
    static <T extends Comparable<T>, V extends T> boolean isIn(T x, V[] y) {
        for (int i = 0; i < y.length; i++)
            if (x.equals(y[i])) return true;

        return false;
    }

    // 泛型構造函數
    public class Gen {
        <T extends Number> Gen(T num) {
            System.out.println(num);
        }
    }

    @Test
    public void test() {
        Integer nums[] = {1, 2, 3, 4, 5};
        if (isIn(2, nums))// 調用泛型方法,不須要指定類型,Java能自動推斷
            System.out.println("2 is in nums");

        new Gen(88);
        new Gen(12.6);
    }
}

 

泛型接口:

public class test {
    interface MinMax<T extends Comparable<T>> {// 泛型接口
        T min();
        T max();
    }

    class MyClass2 implements MinMax<Interger>{}// 非泛型實現方式

    class MyClass<T extends Comparable<T>> implements MinMax<T> {// 泛型實現方式
        T[] vals;
        MyClass(T[] o) {
            vals = o;
        }
        public T min() {
            T v = vals[0];
            for (int i = 1; i < vals.length; i++)
                if (vals[i].compareTo(v) < 0) v = vals[i];
            return v;
        }
        public T max() {
            T v = vals[0];
            for (int i = 1; i < vals.length; i++)
                if (vals[i].compareTo(v) > 0) v = vals[i];
            return v;
        }
    }

    @Test
    public void test() {
        Integer inums[] = {3, 6, 2, 8, 5};
        Character chs[] = {'b', 'r', 'a', 'z'};
        MyClass<Integer> iob = new MyClass<Integer>(inums);
        MyClass<Character> cob = new MyClass<Character>(chs);

        System.out.println(iob.min());// 2
        System.out.println(iob.max());// 8
        System.out.println(cob.min());// a
        System.out.println(cob.max());// z
    }
}

原始類型與遺留代碼:

// 能夠使用不帶參數類型的原始類型,其實是建立了Gen<Object>,只爲了兼容舊代碼,新代碼不能這樣作
Get raw = new Gen(new Double(98.6));

泛型類層次化:

public class test {
    class Gen<T> {
        T ob;
        Gen(T o) {
            ob = o;
        }
        T getob() {
            return ob;
        }
    }

    class Gen2<T> extends Gen<T> {// 擴展了泛型類Gen,並吧T傳遞給Gen
        Gen2(T o) {
            super(o);
        }
    }

    class Gen3<T, V> extends Gen<T> {// 添加本身另外的參數化類型
        V ob2;
        Gen3(T o, V o2) {
            super(o);
            ob2 = o2;
        }
        V getob2() {
            return ob2;
        }
    }

    class Gen4<T> extends Object {// 超類能夠不是泛型類
    }
}

泛型的類型推斷:

MyClass<Integer, String> mcOb = new MyClass<Integer, String>(98,"String");
MyClass<Integer, String> mcOb = new MyClass<>(98,"String");// 建立實例時推斷

if(mcOb.isSame(new MyClass<>(1,"String"))) System.out.println("same");// 傳遞參數時推斷

擦除:

Java經過擦除這個技術來實現泛型。

擦除工做原理:編譯Java代碼時,全部泛型信息被擦除;使用它們的界定類型替換類型參數,若是沒有界定類型則使用Object,而後使用適當的類型轉換。因此泛型只存在於源代碼,運行時沒有泛型。

詳細深刻的內容,這裏不討論。

模糊性錯誤:

class MyClass<T,V>{// 當T和V同類型時,就會引起模糊性錯誤,2個set重載編程一樣類型
    T ob1;
    V ob2;

    void set(T o){ob1 = o;}
    void set(V o){ob2 = o;}
}

泛型的使用限制:

class Gen<T>{
    T ob;
    T vals[];

    Gen(){
        ob = new T();// 不能實例化類型參數
        vals= new T[10];// 不能實例化類型爲參數類型的數組
    }

    static T ob;// 錯誤,不能使用參數類型建立靜態成員
    static T getob(){..}// 錯誤,不能使用參數類型建立靜態成員
}

Gen<Integer> gens[] = new Gen<Integer>[10];// 錯誤,不能建立特定類型的泛型引用數組
Gen<?> gens[] = new Gen<?>[10];// 正確

// 另外泛型類不能擴展Throwable,表明不能建立泛型異常類

十5、lambda表達式

JDK8新增功能

增長了新的語法元素

使API庫增長了新的功能,包括多核環境的並行處理功能(特別是for-each操做)變得容易,以及支持對數據執行管道操做的新的流API

催生了新的Java功能,包括默認方法以及方法引用

2個關鍵結構:

lambda表達式:

  • 本質上是一個匿名方法。這個方法不是用來獨立執行的,而是用於實現函數式接口定義的另外一個方法。
  • 實現函數式接口,一種方法是日常同樣,建立一個類,而後實現方法;而lambda是另外一種方法,使用匿名方法的方式實現。
  • lambda表達式會致使產生一個匿名類。
  • lambda表達式也常常成爲閉包。

函數式接口:

  • 僅包含一個抽象方法的接口,一般表示單個動做。
  • 函數式接口定義了lambda表達式的目標類型。
  • 特別注意:lambda表達式只能用於其目標類型已被指定的上下文中。
  • 另外,函數式接口有時候被稱爲SAM類型,意思是單抽象方法(Single Abstract Method)

 應用實例:

()->123.45
至關於
double myMeth(){return 123.45;}

()->Math.randow()*100
()->(n%2)==0

// 函數式接口,只有一個抽象方法的接口
// JDK8以前,全部接口方法隱式都是抽象方法
// 可是JDK8以後,能夠接口聲明默認方法
// 全部JDK8及之後,沒有默認實現的接口方法,纔是隱式地是抽象方法
interface MyNumber{
    double getValue();
}

MyNumber myNum;// 定義一個函數式接口
myNum = ()->123.45;// 賦值lambda表達式,至關於建立了一個匿名類,實現了MyNumber接口,該方法的內容等於等號後面部分。
System.out.println(myNum.getValue())// 有具體實現的接口,能夠調用方法

// 帶參數的lambda表達式
(n)->(n%2)==0// 參數類型能夠根據接口來推線,能夠不指定參數類型
(int n)->(n%2)==0// 顯式指定參數類型

// 多個參數
NumericTest2 isFactor  = (n,d)->(n%d)==0;

// 使用代碼塊的lambda表達式
NumericFunc factorial = (n) -> {
    int result = 1;
    
    for(int i=1; i <= n; i++)
        result = i * result;
        
    return result;
};

// 泛型函數式接口
// lambda表達式不能指定類型參數,可是函數式接口能夠是泛型
interface SomeFunc<T>{
    T func(T t);
}
SomeFunc<String> func1 = (str) -> {... return str;};
func1.func("func1");
SomeFunc<Integer> func2 = (val) -> {... return val;};
func2.func(1);

// 做爲參數傳遞lambda表達式
interface StringFunc{
    String func(String n);
}
public String stringOp(StringFunc,String s)
{
    return StringFunc.func(s);
}

StringFunc func = (n)->{return n+"!";};
String result = stringOp(func,"no");

// 若是lambda表達式拋出異常,接口的throws子句應該匹配該異常
interface StringFunc{
    String func(String n) throws NullException;
}
StringFunc func = (n)->{
    if(n.equals(""))
        throw new NullException();
    return n+"!";
};

lambda表達式和變量捕獲:

lambda表達式中,能夠訪問:

  • 能夠獲取或者是外層類的實例或靜態變量的值
  • 能夠隱式或顯式地訪問this變量,引用lambda表達式外層類的調用實例
  • 變量捕獲:
    • lambda表達式只能使用實質上是final(第一次賦值後,值就不變化)的局部變量;
    • lambda表達式不能修改外層做用域內的局部變量,由於修改會移除其實質final狀態

方法引用:

在上面,要傳入一個函數式接口的實例,必須使用lambda語句建立一個匿名實現。

方法引用:若是咱們在其餘類中,已有方法恰好實現了這個接口,那麼咱們能夠直接引用這個方法,傳入給這個函數式接口參數

原理:方法引用會建立函數式接口的一個實例。

// 靜態方法引用
interface StringFunc{
    String func(String n);
}
class MyStringOps{
    static String strReverse(String str){
        ....
        return ...;
    }
}
static String stringOp(StringFunc sf,String s){
    return sf.func(s);
}
String outStr = stringOp(MyStringOps::strReverse, "str1");

// 實例方法引用
class MyStringOps{
    String strReverse(String str){
        ....
        return ...;
    }
}
static String stringOp(StringFunc sf,String s){
    return sf.func(s);
}
MyStringOps ops = new MyStringOps();
String outStr = stringOp(ops::strReverse, "str1");

// 類的實例方法的引用
// 上面引用的是類的靜態方法,實例的方法;如今還能夠引用類的實例方法
// 此時,函數式接口匹配的方法是,第一個參數匹配調用對象,後面的參數再匹配實例方法的參數
interface MyFunc<T>{
    boolean func(T v1,T v2);
}
class HighTemp{
    boolean sameTemp(HighTemp ht2){
        ...
    }    
}

static <T> void do(MyFunc<T> f,T t1,T t2){
    f.func(t1,t2);// 執行的是t1.sameTemp(t2)
}
// HighTemp的sameTemp方法只有一個參數,可是調用類的實例方法,第一個參數須要匹配調用對象
do(HighTemp::sameTemp,new HighTemp(1),new HighTemp(2));

// super::name 能夠引用發放的超類版本

// 泛型中的方法引用
// 泛型方法MyArrayOps::<Integer>countMatching
// 泛型類MyArrayOps<Integer>::countMatching
// 類型也能夠不寫,經過類型推斷
interface MyFunc<T>{
    int func(T[] vals, T v);
}
class MyArrayOps{
    static <T> int countMatching(T[] valus,T v){
        int count = 0;
        for(int i=0;i<vals.length;i++)
            if(vals[i]==v)count++;
        return count;
    }
}
class Demo{
    static <T> int myOp(MyFunc<T> f,T[] vals,T v){
        return f.func(vals,v);
    }
    public static void main(String args[]){
        Integer[] vals = {1,2,3,4,2,2,3,4};
        String[] strs = {"One","Two","Three","Two"};
        int count;
        
        count = myOp(MyArrayOps::<Integer>countMatching,vals,4);
        count = myOp(MyArrayOps::<String>countMatching,strs,"Two");
    }
}

// Collection,如Compare接口,不必定須要實現接口,並建立對應實例
// 能夠考慮建立一個靜態方法,與Comparator的compare方法兼容,而後使用方法引用
class MyClass{
    private int val;
    MyClass(int v){val = v;}
    int getVal(){return val;}
}
class UseMethodRef{
    static int compareMC(Myclass a,MyClass b){
        reutrn a.getVal() - b.getVal();
    }
    public static void main(String args[])
    {
        ArrayList<MyClass> a1 = new ArrayList<MyClass>();
        a1.add....
        MyClass maxValObj = Collections.max(a1,UseMethodRef::compareMC);
    }
}

構造函數引用:

暫略,不想看了。

預約義的函數式接口:

爲了不常常本身定義函數式接口,JDK8提供了java.util.function,提供了預約義的函數式接口

十6、字符串處理

String、StringBuffer、StringBuilder

StringBuffer、StringBuilder用於能夠修改的字符串

StringBuilder,StringBuilder不是同步的,因此不是線程安全,優點在於性能更高

若是字符串被多個線程修改,沒有使用其它同步措施的話,須要使用StringBuffer

十7、java.lang

暫略,大部分是接口和API

public interface Iterable<T> {
    // 返回迭代器
    Iterator<T> iterator();

    // 迭代每一個元素執行action代碼
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    // 返回被迭代序列的Spliterator
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

十8、java.util集合框架

一、集合框架概述

集合框架以前:Java提供了特定的類以存儲和管理對象組,如Dictionary、Vector、Stack和Properties。

問題:缺乏集中、統一的主體,不易擴展,不易改造。

集合框架的目標:

  • 一、高性能。基本集合(動態數組、鏈表、樹和哈希表)的實現是高效率的。
  • 二、統1、高互操做性。框架必須容許不一樣類型的集合以相似的方式進行工做,而且具備高度的互操做性。
  • 三、易擴展、易改造。
  • 四、必須將標準數組集成到集合框架中的機制。

爲了知足這些目標,Java提供了:

  • 一套標準接口和實現:整個集合框架基於一套標準接口進行構造,提供了這些接口的一些能夠直接使用的標準實現(如LinkedList、HashSet、TreeSet),也能夠實現本身的集合。
  • 集合算法:算法是集合機制中的另外一個重要部分。算法操做集合,而且被定義爲Collections類中的靜態方法。因此全部集合均可以使用它們,每一個集合都不須要實現本身的版本,算法爲操做集合提供了標準方法。
  • Iterator接口,迭代器:爲訪問集合中的元素提供了通用的、標準的方式,每次訪問一個元素。每一個集合都提供了迭代器。
  • spliterato:JDK8提供了一種新的迭代器,叫spliterator,用於支持並行迭代。支持spliterator的接口有Spliterator和支持基本類型的幾個嵌套接口。JDK8還添加了用於基本類型的迭代器接口,例如PrimitiveIterator和PrimitiveIterator.OfDouble。
  • 處理映射:除了集合外,框架還定義了一些映射接口和類。映射存儲鍵值對。雖然映射是集合框架的組成部分,可是嚴格意義上說,他們不是結婚。不過,能夠得到映射的集合視圖(collection-view)。這種視圖包含來自映射的元素,並存儲在集合中。所以,也能夠做爲一種選擇,能夠想處理集合同樣處理映射內容。

新的JDK爲集合框架帶來的改變:

  • 一、泛型:泛型從根本上改變了集合框架,新增的泛型使整個集合框架對泛型進行了從新設計。因此集合如今都是泛型,許多操做集合的方法如今都是使用泛型參數。
  • 二、自動裝箱:自動裝箱使得使用基本類型更加容易。集合只能存儲引用,不能存儲基本類型值,之前須要手動裝箱,如今就再也不須要了。
  • 三、for-each風格的for循環:合框架中全部集合類進行了從新設計以實現Iterable接口,因此能夠使用for-each風格的for循環遍歷集合。之前須要使用迭代器,如今能夠使用for循環替代。

二、集合接口

除了集合接口外,集合還使用Comparator、RandomAccess、Iterator以及ListIterator接口,這些後面探討。JDK8開始,還使用Spliterator接口。

Collection接口

Collection接口是集合框架的基礎,全部定義集合的類都必須實現這個接口,是一個泛型接口。

interface Collection<E> //E是存儲對象的類型

Collection擴展了Iterable接口,因此全部集合均可以使用for-each風格的for循環

Collection聲明瞭全部集合將擁有的核心方法

異常:

  • UnsupportedOperationExceiption:不能被修改集合執行修改集合的方式時拋出
  • ClassCastException:一個對象和另外一個對象不兼容時拋出,如試圖將一個不兼容的對象添加到集合中
  • NullPointerException:視圖在不容許存儲null對象的集合中存儲null對象
  • IllegalArgumentException:使用參數無效
  • IllegalStateException:未長度固定且已滿的集合添加元素

核心方法總結:添加、刪除、檢查是否包含、獲取迭代器、轉換數組、獲取流

List接口

擴展Collection,並聲明瞭用來存儲一連串元素的集合的行爲。

能夠使用從0開始的索引,經過元素位置插入或訪問元素。

能夠包含重複元素

interface List<E> //E是存儲對象的類型

 

Set接口

Set接口定義了組,擴展了Collection接口,聲明瞭集合中不容許有重複元素的組行爲

沒有定義本身的其它方法,添加劇復元素的時候,add()方法返回false

interface Set<E> //E是存儲對象的類型

SortedSet接口

SortedSet擴展了Set接口,並聲明以升序進行排序的組行爲。

interface SortedSet<E> //E是存儲對象的類型

NavigableSet接口

NavigableSet接口擴展了SortedSet接口,而且聲明瞭支持基於最接近匹配原則檢索元素的集合行爲

interface NavigableSet<E> //E是存儲對象的類型

Queue接口

Queue接口擴展了Collection接口,聲明瞭隊列的行爲,隊列一般是先進先出隊列,但也有其餘準則的隊列類型。

interface Queue<E> //E是存儲對象的類型

Deque接口

Deque接口擴展了Queue接口,而且聲明瞭雙端隊列行爲,既能夠先進先出,也能夠後進先出

interface Deque<E> //E是存儲對象的類型

三、集合類

集合接口的標準實現

ArrayList

ArrayList擴展了AbstractList類並實現了List接口

class ArrayList<E> //E是存儲對象的類型

用於按需增加的動態數組,Java裏面的數組長度是固定的,定義後不能增加或縮小。

// 構造函數
ArrayList()
ArrayList(Collection<? extends E> c) // 使用一個集合進行初始化
ArrayList(int capacity) // 初始容量

使用示例

public class test {
    @Test
    public void test() {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("a");
        arrayList.add("d");
        arrayList.add("c");
        arrayList.add("d");
        arrayList.add(1, "b");
        System.out.println(arrayList);// [a, b, d, c, d]
        System.out.println(arrayList.size());// 5

        arrayList.remove("d");// 從前日後查找,找到第一個刪除
        System.out.println(arrayList);// [a, b, c, d]
        System.out.println(arrayList.size());// 4

        arrayList.remove("d");
        System.out.println(arrayList);// [a, b, c]
        System.out.println(arrayList.size());// 3

        arrayList.ensureCapacity(12);// 一次性增長內存,提高性能;避免每次增長一個元素就分配一次內存
        System.out.println(arrayList.size());// 仍爲3

        arrayList.trimToSize();// 減小內存到恰好容納如今的元素
        System.out.println(arrayList.size());// 仍爲3

        // 轉換爲數組
        Object[] array1 = arrayList.toArray();// 方法1,轉換爲Object數組
        // 經常使用方法2,轉換爲特定類型數組
        String[] array2 = new String[arrayList.size()];
        arrayList.toArray(array2);
        for (Object item : array1) System.out.print(item + ",");// a,b,c,
        System.out.println();
        for (Object item : array2) System.out.print(item + ",");// a,b,c,
    }
}

LinkedList類

LinkedList類擴展了AbstractSequentialList類,實現了List、Deque以及Queue接口,而且提供了一種鏈表數據結構

class LinkedList<E> //E是存儲對象的類型
// 構造函數
LinkedList()
LinkedList(Collection<? extends E> c)
public class test {
    @Test
    public void test() {
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("F");
        linkedList.add("B");
        linkedList.add("D");
        linkedList.add("E");
        linkedList.add("C");
        linkedList.add("Z");
        linkedList.add("A");
        linkedList.add(1, "A2");
        System.out.println(linkedList);// [F, A2, B, D, E, C, Z, A]

        linkedList.remove("F");
        linkedList.remove(2);
        System.out.println(linkedList);// [A2, B, E, C, Z, A]

        linkedList.removeFirst();
        linkedList.removeLast();
        System.out.println(linkedList);// [B, E, C, Z]

        String val = linkedList.get(2);
        linkedList.set(2, val + "Changed");
        System.out.println(linkedList);// [B, E, CChanged, Z]
    }
}

HashSet類

HashSet類擴展了AbstractSet類並實現了Set接口,用於建立使用哈希表存儲元素的集合。

散列機制優點是及時集合較大,add()、contains()、remove()、size()的方法執行時間保持不變

class HashSet<E> //E是存儲對象的類型
// 構造函數
HashSet()
HashSet(Collection<? extends E> c)// 使用集合初始化
HashSet(int capacity)// 使用容量初始化,默認16
HashSet(int capacity, float fillRatio)// 容量和填充率初始化,填充率是0.0到1.0之間,集合中數量達到填充率,就會擴展和哈希組,默認0.75

HashSet沒有本身的方法,只有超類和接口的方法

public class test {
    @Test
    public void test() {
        HashSet<String> hs = new HashSet<String>();
        hs.add("b");
        hs.add("c");
        hs.add("d");
        hs.add("e");
        hs.add("a");
        hs.add("a");
        System.out.println(hs);// [a, b, c, d, e] 不可重複且沒有順序
    }
}

LinkedHashSet類

LinkedHashSet擴展了HashSet類,沒有添加本身的方法

class LinkedHashSet<E> //E是存儲對象的類型

LinkedHashSet維護條目中的一個鏈表,鏈表中條目順序就是插入順序,能夠按照插入順序迭代。

同時toString()方法也是按照插入順序輸出

public class test {
    @Test
    public void test() {
        LinkedHashSet<String> hs = new LinkedHashSet<String>();
        hs.add("b");
        hs.add("c");
        hs.add("d");
        hs.add("a");
        hs.add("e");
        hs.add("a");
        System.out.println(hs);// [b, c, d, a, e] 按照插入順序輸出,重複的則不插入
    }
}

TreeSet

TreeSet擴展了AbstractSet類並實現了NavigableSet接口,用於建立使用樹存儲的組。

對象以升序存儲,訪問和檢索速度至關快,使得對存儲大量的、必須可以快速查找的有序信息來講,TreeSet是極佳選擇。

class TreeSet<E> //E是存儲對象的類型
// 構造函數
TreeSet()// 建立空樹,按照元素的天然順序以升序進行存儲
TreeSet(Collection<? extends E> c)// 構建一個包含集合c中元素的樹
TreeSet(Comparator<? super E> comp)// 構建一個空樹,按照comp指定的比較器進行存儲
TreeSet(SortedSet<E> ss)// 構建一個包含ss中元素的樹
public class test {
    @Test
    public void test() {
        TreeSet<String> ts = new TreeSet<String>();

        ts.add("C");
        ts.add("A");
        ts.add("B");
        ts.add("E");
        ts.add("F");
        ts.add("D");

        System.out.println(ts);// [A, B, C, D, E, F] 自動排序
        System.out.println(ts.subSet("C","F"));// [C, D, E],使用NavagalbeSet接口的方法檢索TreeSet元素
    }
}

PriorityQueue類

PriorityQueue擴展了AbstractQueue類並實現了Queue接口,用於建立根據隊列的比較器來判斷優先次序的隊列。

PriorityQueue是動態的、按需增加的。

class PriorityQueue<E> //E是存儲對象的類型
// 構造函數
PriorityQueue()// 起始容量爲11
PriorityQueue(int capacity)// 指定初始容量
PriorityQueue(Comparator<? super E> comp)// 指定比較器
PriorityQueue(int capacity,COmparator<? super E> comp)// 指定容量和比較器
PriorityQueue(Collection<? extends E> c)// 使用集合C來初始化
PriorityQueue(PriorityQueue<? extends E> c)// 使用集合C來初始化
PriorityQueue(SortedSet<? extends E> c)// 使用集合C來初始化

若是沒有指定比較器,將使用隊列中存儲的數據類型的默認比較器。

默認比較器以升序對隊列進行排序。

使用comparator()方法獲取比較器,若是隊列使用的是天然順序,則返回null

雖然能夠使用迭代器遍歷PriorityQueue,可是迭代順序是不肯定的。

使用PriorityQueue,應該使用offer()和poll()這類由Queue接口定義的方法 

ArrayDeque類

ArrayDeque擴展了AbstractCollection類並實現了Deque接口,沒有添加本身的方法。

ArrayDeque是動態數組,沒有容量限制(Deque接口支持限制容量的實現,但不是必須的)

class ArrayDeque<E> //E是存儲對象的類型
// 構造函數
ArrayDeque()// 空的雙端隊列,初始容量是16
ArrayDeque(int size)// 指定容量
ArrayDeque(COllection<? extends E> c)// 使用集合來初始化
public class test {
    @Test
    public void test() {
        ArrayDeque<String> adq  = new ArrayDeque<String>();
        adq.push("A");
        adq.push("B");
        adq.push("D");
        adq.push("E");
        adq.push("F");
        System.out.println(adq);// [F, E, D, B, A]
        while (adq.peek()!=null)
            System.out.print(adq.poll()+",");// F,E,D,B,A,
    }
}

EnumSet類

EnumSet擴展了AbstractSet並實現了Set接口,專門用於枚舉類型的元素。

class EnumSet<E extends Enum<E>> //E是存儲對象的類型

EnumSet類沒有定義構造函數,而是使用工廠方法來建立對象

四、經過迭代器訪問集合

若是但願遍歷集合中的元素,方法之一是使用迭代器。

迭代器是實現了Iterator或ListIterator接口的對象。

Iterator接口容許遍歷集合,獲取或移除元素。

ListIterator接口擴展了Iterator接口,容許雙向遍歷列表,而且容許修改元素。

interface Iterator<E> //E是存儲對象的類型
interface ListIterator<E> //E是存儲對象的類型

使用迭代器

iterator:

獲取迭代器:每一個集合類都提供了iterator()方法,方法返回一個指向集合開頭的迭代器

具體步驟:

  • 一、調用集合的iterator()方法,獲取指向集合開頭的迭代器
  • 二、創建一個hasNext()方法調用循環,只要hasNext()返回true,就繼續迭代
  • 三、循環中,調用next()方法獲取每一個元素

對於實現List接口的集合,還能夠調用listIterator()方法來獲取迭代器,這種方式提供了向前和向後2個方向的訪問集合的能力,並容許修改元素。除此以外,2個用法相似。

public class test {
    @Test
    public void test() {
        ArrayList<String> a1 = new ArrayList<String>();
        a1.add("C");
        a1.add("A");
        a1.add("E");
        a1.add("B");
        a1.add("D");
        a1.add("F");
        System.out.println(a1);// [C, A, E, B, D, F]

        Iterator<String> itr = a1.iterator();
        while (itr.hasNext()) {
            String element = itr.next();
            System.out.print(element + ",");// C,A,E,B,D,F,
        }
        System.out.println();

        ListIterator<String> litr = a1.listIterator();
        while (litr.hasNext()) {
            String element = litr.next();
            litr.set(element + "+");
        }
        System.out.println(a1);// [C+, A+, E+, B+, D+, F+]

        itr = a1.iterator();
        while (itr.hasNext()) {
            String element = itr.next();
            System.out.print(element + ",");// C+,A+,E+,B+,D+,F+,
        }
        System.out.println();

        while (litr.hasPrevious()) {
            String element = litr.previous();
            System.out.print(element + ",");// F+,D+,B+,E+,A+,C+,
        }
        System.out.println();
    }
}

for-each循環代替迭代器:

若是不修改集合的內容,也不用反向獲取元素,那麼使用for-each風格的for循環遍歷集合一般更加方便。

for循環能夠遍歷全部實現Iterable接口的集合對象,而全部集合類都實現了這個接口,因此均可以用for循環操做。

public class test {
    @Test
    public void test() {
        ArrayList<Integer> vals = new ArrayList<Integer>();
        vals.add(1);
        vals.add(2);
        vals.add(3);
        vals.add(4);
        vals.add(5);
        System.out.println(vals);// [1, 2, 3, 4, 5]

        for(int v :vals)
            System.out.print(v+",");// 1,2,3,4,5,
        System.out.println();

        int sum = 0;
        for(int v:vals)
            sum+=v;
        System.out.println(sum);// 15
    }
}

Spliterator:

JDK8新增一種叫splitertor的迭代器,由Spliterator接口定義。

Spliterator用於循環遍歷元素序列。

它提供的方法遠比Iterator或ListIterator多,最重要的一點是它支持並行迭代序列的一部分。

即便用不到並行編程,也能夠使用Spliterator,其中一個緣由是它把hasNext和next操做合併到一個方法中,從而提供了效率

interface Spliterator<T> //T是被迭代元素的類型

暫略,須要lambda表達式知識

RandomAccess接口:

RandomAccess接口不包括成員。然而經過實現這個接口,能夠代表集合支持高效地隨機訪問其中的元素。儘管集合可能支持隨機訪問,可是可能沒有這麼高效。

經過檢查RandomAccess接口,客戶端代碼能夠在運行時肯定集合是否適合特定類型的隨機訪問操做——特別是當將他們應用於大的集合時(能夠使用instance of來判斷類是否實現了這個接口)。

ArrayList和遺留的Vector類實現了RandomAccess接口。

五、使用映射

映射是存儲鍵和值之間關係(鍵值對)的對象。

鍵和值都是對象,鍵必須惟一,但值能夠重複。

某些映射能夠接收null鍵和null值,其它不能。

映射沒有實現Iterable接口,因此不能使用for-each風格的for循環,也不能獲取迭代器。

可是能夠獲取映射的集合視圖,集合視圖容許使用for循環和迭代器。

映射接口:

Map接口:

Map接口將惟一鍵映射到值。給定鍵和值就能夠在Map對象中存儲;存儲後能夠使用鍵來檢索值。

interface Map<K,V>// K是鍵的類型,V是值的類型。

映射圍繞2個基本方法:get()、put()

使用entrySet()方法,返回一個Set對象,包含映射中元素。

使用keySet()方法,返回一個Set對象,做爲鍵的集合視圖。

使用values()方法,返回一個Set對象,做爲值的集合視圖。

修改一個集合會影響其餘集合,由於集合的數據是引用映射內的數據。

集合視圖是將映射集成到集合框架中的手段。

SortedMap接口

SortedMap接口擴展了Map接口,確保條目以鍵的升序保存。

interface SortedMap<K,V>// K爲鍵類型,V爲值類型

有序映射支持很是高效的子映射操做,如headMap()、tailMap()或subMap()方法。

NavigableMap接口

NavigableMap接口擴展了SortedMap接口,支持基於最接近匹配原則的條目檢索行爲,即支持檢索與給定的一個或多個鍵最相匹配的條目。

interface NavigableMap<K,V>

Map.Entry接口

Map.Entry接口提供了操做映射條目的功能。

Map接口聲明的entrySet()方法返回一個包含映射條目的Set對象。

組的全部元素都是Map.Entry對象。

interface Map.Entry<K,V>

另外JDK8添加了2個靜態方法:comparingByKey()和comparingByValue()。

前者返回根據鍵比較條目的Comparator對象,後者返回根據值比較條目的Comparator對象。

映射類

有幾個類實現了映射接口

AbstractMap是全部具體映射實現的超類。

WeakHasMap實現了使用「弱鍵」的映射,鍵不在使用時能夠被垃圾回收,這裏不討論。

一、HashMap類

HashMap擴展了AbstractMap類並實現了Map接口,沒有添加本身的方法。

他使用哈希表存儲映射,使得即便比較大的集合,get()和put()方法執行時間保持不變

class HashMap<K,V>
// 構造函數
HashMap()
HashMap(Map<? extends K, ? extends V> m)// 使用m中元素初始化
HashMap(int capacity)// 使用容量初始化
HashMap(int capacity, float fillRatio)// 使用容量和填充率初始化,默認是16,0.75
public class test {
    @Test
    public void test() {
        HashMap<String,Double> hm = new HashMap<String,Double>();

        hm.put("a",new Double(11.24));
        hm.put("d",new Double(22.24));
        hm.put("e",new Double(33.24));
        hm.put("b",new Double(44.24));
        hm.put("c",new Double(55.24));

        Set<Map.Entry<String,Double>> set = hm.entrySet();

        for(Map.Entry<String,Double>me:set){
            System.out.print(me.getKey()+":"+me.getValue()+",");// a:11.24,b:44.24,c:55.24,d:22.24,e:33.24,
        }
        System.out.println();

        double balance = hm.get("a");
        hm.put("a",balance+100);

        System.out.println(hm.get("a"));// 111.24
    }
}

TreeMap類

TreeMap擴展了AbstractMap類並實現了NavigableMap接口,該類用於建立存儲在樹結構中的映射。

TreeMap提供了有序存儲鍵值對的搞笑手段,並支持快速檢索。

與哈希映射不一樣,樹映射確保元素以鍵的升序存儲。

class TreeMap<K,V>
// 構造函數
TreeMap()// 按鍵的天然順序存儲
TreeMap(Comparator<? super K> comp)// 使用比較器comp進行排序
TreeMap(Map<? extends K, ? extends V> m)// 使用m中條目初始化樹映射,使用鍵的天然順序進行排序
TreeMap(SortedMap<K, ? extends V> sm)// 使用sm中條目初始化樹映射,使用sm相同順序進行排序

TreeMap類的映射方法沒有超出NavagableMap接口和AbstractMap類定義的那些方法。

public class test {
    @Test
    public void test() {
        TreeMap<String,Double> tm = new TreeMap<String,Double>();
        tm.put("a",new Double(11.24));
        tm.put("d",new Double(22.24));
        tm.put("e",new Double(33.24));
        tm.put("b",new Double(44.24));
        tm.put("c",new Double(55.24));
        Set<Map.Entry<String,Double>> set = tm.entrySet();

        for(Map.Entry<String,Double>me:set){
            System.out.print(me.getKey()+":"+me.getValue()+",");// a:11.24,b:44.24,c:55.24,d:22.24,e:33.24, 按照鍵升序排列
        }
        System.out.println();

        double balance = tm.get("a");
        tm.put("a",balance+100);

        System.out.println(tm.get("a"));// 111.24
    }
}

LinkedHashMap類

LinkedHashMap擴展了HashMap類,在映射中以插入條目的順序維護一個條目鏈表,從而能夠按照插入順序迭代整個映射。

也就是說,當遍歷LinkedHashMap的集合視圖時,將以元素的插入順序返回元素。也能夠建立按照最後訪問的順序返回元素的LinkedHashMap。

class LinkedHasMap<K,V>
// 構造函數
LinkedHashMap()
LinkedHashMap(Map<? extends K, ? extends V> m)// 使用m中元素初始化LinkedHashMap
LinkedHashMap(int capacity)// 指定容量
LinkedHashMap(int capacity, float fillRatio)// 指定容量和填充率,默認16,0.75
LinkedHashMap(int capacity, float fillRatio, boolean Order)// Order爲true,使用訪問順序;Order爲false,使用插入順序,默認的是插入順序

LinkedHashMap除了繼承自HashMap定義的方法外,只添加了一個方法,removeEldestEntry()

protected bollean removeEldestEntry(Map.Entry<k,V> e)

這個方法由put()和putAll()調用。最舊的條目由e傳入。

默認狀況下這個方法返回false,而且不執行任何操做;重寫這個方法,能夠使LinkedHashMap移除映射中最舊的條目。

IdentityHashMap類

IdentityHashMap擴展了AbstractMap類並實現了Map接口。除了當比較元素時使用引用相等性外,其它方面和HashMap相似

class IdentityHasMap<k,V>

API文檔明確指出IdentityHashMap不用於通用目的

EnumMap類

EnumMap擴展了AbstractMap類並實現Map接口,是專門爲使用枚舉類型的值設計的。

class EnumMap<K extends Enum<K>,V>
// 構造函數
EnumMap(Class<K> kType)// 建立類型爲kType的空EnumMap
EnumMap(Map<K, ? extends V> m)// 建立一個包含m中相同條目的EnumMap
EnumMpa(EnumMap<K, ? extends V> em)// 建立一個使用em中的值進行初始化的EnumMap

EnumMap類沒有定義本身的方法。

六、比較器

TreeSet和TreeMap使用有序順序存儲元素。

比較器精肯定義了有序順序的含義。

默認狀況,Java使用天然循序爲這些元素排序(如ABCD,1234等),而比較器可讓咱們自定義順序

interface Comparator<T>

JDK8前,Comparator接口定義了2個方法

int compare(T obj1, T obj2)// obj1大於obj2則返回正數
boolean equals(object obj)// 若是obj和調用對象都是比較器,且使用相同的排序規則,則返回true,不然返回false;通常不須要重寫equals方法

JDK8經過默認接口方法和靜態接口方法,增長了不少新功能

default Comparator<T> reversed()// 得到一個反轉的比較器
static <T extends Comparable<? super T>> Comparator<T> reverseOrder()// 返回一個顛倒元素的天然順序比較器
static <T extends Comparable<? super T>> Comparator<T> naturalOrder()// 返回一個天然順序比較器
static <T> Comparator<T> nullsFirst<Comparator<? super T> comp)// 支持處理null值,並認爲null比其餘值小
static <T> Comparator<T> nullsLast<Comparator<? super T> comp)// 支持處理null值,並認爲null比其餘值大
// thenComparing:當第一次比較結果相等時,則使用這個比較器執行第二次比較
// 三種形式
default Comparator<T> thenComparing(Comparator<? super T> thenByComp)// 指定第二次使用的比較器
default <U extends Comparable<? super U> Comparator<T> thenComparing(Function<? super T, ? extends U> getKey)// getKey引用的函數用於獲取下一個比較鍵
default <U> Comparator<T> thenComparing(Function<? super T, ? extends U> getKey,Comparator<? super U> keyComp)// keyComp指定了用於比較鍵的比較器
// Comparator還爲基本類型添加了以下所示的專用版本方法
// 這些方法中,getKey引用的函數用於獲取下一個比較鍵
static <T> Comparator<T> ComparingDouble(ToDoubleFunction<? super T> getKey)
static <T> Comparator<T> ComparingInt((ToIntFunction<? super T> getKey)
static <T> Comparator<T> ComparingLong((ToLongFunction<? super T> getKey)

使用比較器代碼(待補充)

七、集合算法

集合框架定義了一些能夠用於集合和映射的算法,被定義在Collections類的靜態方法中

不少方法,待補充

八、Arrays類

Arrays類提供了對數組操做有用的方法,有助於鏈接集合和數組。

如下將解釋Arrays類定義的每一個方法

待補充

九、遺留的類和接口

早期的java.util包沒有包含集合框架,而是定義了幾個類和一個接口,用來提供存儲對象方法的專業方法。

注意現代集合類都不是同步的,可是全部遺留類都是同步的,固然能夠使用Collection提供的算法很容易實現同步。

包括

  • Enumeration接口
  • Vector類
  • Dictionary類
  • Hashtable類
  • Properties類、store()和load()方法

十9、java.util其它工具類(略)

二10、java.io(略)

二11、探究NIO(略)

二12、聯網(略)

二十3、Applet(略)

二十4、事件處理(略)

二十5、AWT介紹:使用窗口、圖形和文本(略)

二十6、使用AWT控件、佈局管理器和菜單(略)

二十7、圖像(略)

二十8、併發使用工具(略)

二十9、流API

流的概念:流是數據的渠道。

流表明一個對象序列。

流操做數據源,如數組或集合。

流自己不存儲數據,只是移動數據,移動過程當中可能對數據執行過濾、排序或其餘操做。

通常流操做不會修改數據源,而是建立一個新的流,包含過濾、排序或其餘操做後的結果。

流接口

 

 

終端操做:會消費流,被消費後,流不能重用。

中間操做:會產生另外一個流。中間操做不是當即發生,是在新流上執行完終端操做後,中間操做纔會發生,稱爲延遲行爲,能讓流API更加高效地執行。

另外一個關鍵點:

無狀態:獨立於其餘元素處理每一個元素。如過濾,filter()

有狀態:某個元素處理以來其餘元素。如排序,sorted()

注意,並行處理流時,無狀態和有狀態區別尤爲重要,由於有狀態操做可能須要幾回處理才能完成。

 

Stream操做是對象引用,因此增長了如下幾個接口支持處理基本類型流,都擴展了BaseStream

DoubleStream

IntStream

LongStream

重點關注Stream,基本類型流處理上基本相同

 

 獲取流:

一、COllection接口被擴展,包含2個獲取集合流的方法

 

 補充代碼

 

 縮減操做

基於任意條件,從流中返回一個值。全部縮減操做都是終端操做。

 

 

 

 

三10、正則表達式和其它包(略)

三11、Swing簡介(略)

三12、探究Swing(略)

三十3、Swing菜單簡介(略)

三十4、JavaFX GUI編程簡介誒(略)

三十5、探究JavaFX控件(略)

三十6、JavaFX菜單簡介(略)

三十7、Java Bean

這個是Java的組件架構,經過必定的規範保證組件能夠重用和互操做;可是有Spring框架後,Spring框架中的Bean是基於POJO的,因此Java Bean的意義不大了。(我的觀點)

軟件行業一直在探索,以實現基於組件方式的可重用和互操做性。

Java Bean是一種組件架構,但願開發軟件時,能夠利用這些軟件組件來構建複雜的系統。

例如電子行業的電阻器、電容器、傳感器等。

那麼設計這能夠選擇組件,理解他們的功能,並把他們集成到應用程序中。

Java Bean:

Java語言書寫,而且遵照JavaBean API規範

軟件組件,被設計成能夠在不一樣環境下重用。

功能能夠是獲取庫存值,又或者預測股票走勢。

優點:

內省:

  • JavaBean的核心是內省,內省是分析Bean的過程,用於肯定Bean的功能。
  • 這是Java Bean API的本質特徵,容許其餘應用程序獲取關於組建的信息。
  • 有了內省機制,Java Bean技術才能起做用。

2種方式指示Bean應當暴露哪些屬性、事件和方法:

  • 簡單的命名約定,這些約定使內省機制可以推斷出與Bean相關信息
  • 提供一個擴展了BeanInfo的接口的附加類,顯式提供這些信息

屬性的設計模式:

  • 屬性是Bean狀態的子集。
  • 賦給屬性的值決定了組件的行爲和外觀。
  • 屬性經過setter方法設置,經過getter方法獲取
  • 2種屬性:簡單屬性、索引屬性

簡單屬性:

補充代碼

索引屬性:

補充代碼

事件的設計模式

補充代碼

方法與設計模式:

  • 設計模式不能用於命名非屬性方法。
  • 內省機制可以發現Bean的全部公有方法,可是不能顯示保護方法和私有方法。

BeanInfo接口:

  • 顯式控制哪些信息可得
  • 補充代碼

綁定屬性與約束屬性:

具備綁定屬性的Bean:

  • 屬性發生變化時會產生事件。
  • 時間的類型是PropertyChangeEvent,而且事件將被髮送到以前註冊的對接收這種通知感興趣的對象。
  • 處理這種事件的類必須實現PropertyChangeListener接口。

具備約束屬性的Bean:

  • 當嘗試修改約束屬性的值會產生事件。
  • 事件的類型也是PropertyChangeEvent,而且也將被髮送到以前的對接收這種通知感興趣的對象。
  • 可是,其它對象能夠拋出PropertyVetoException異常來否決建議的修改。
  • 這種能力使得Bean能夠根據運行時環境來進行不一樣的操做。
  • 處理這種事件的類必須實現VetoableChangeListener接口。

持久性:

  • 持久性是保存Bean當前狀態到非易失性存儲器的能力,以及以後檢索他們的能力,包括Bean的屬性值和實例變量的值。
  • Java類庫提供的對象串行化能力,能夠用於爲Bean提供持久化。
  • 串行化Bean:讓Bean實現java.io.Serializable接口,只是一個簡單的標記接口。
  • 實現後無需其它操做,使得Bean能夠自動完成串行化。
  • 自動串行化還能進行繼承。
  • 使用transient關鍵字能夠阻止某個實例變量參與串行化。
  • 若是沒有實現該接口,能夠經過實現java.io.Externalizable等方式來自行提供串行化,不然容器態保存組件的配置信息。

定製器:

  • Bean開發者能夠提供定製器,用於幫助其餘開發者配置Bean。
  • 定製器能夠提供一步步的指導,以完成再特定上下文中使用組件必須遵循的步驟。
  • 還能夠提供在線文檔。
  • 對於開發定製器,Bean開發者擁有很大的靈活性,能夠根據市場對產品進行微調。

Java Bean API:

Java Bean功能是由java.beans包的一組類和接口提供的。

三十8、servlet

applet動態擴展Web瀏覽器功能;而servlet是在Web鏈接的服務器端執行的小程序,動態擴展了Web服務器的功能。

背景:

Web瀏覽器如何與服務器之間進行協做並最終爲用戶提供內容呢?

請求靜態Web頁面:

  • 用戶在瀏覽器輸入URL地址
  • 瀏覽器產生HTTP請求,發送到Web服務器
  • Web服務器將HTTP請求映射到特定文件
  • Web服務器在HTTP響應中,把文件返回到瀏覽器,響應中HTTP頭指明瞭內容的類型
  • MIME(多用途Internet郵件擴展,Multipurpose Internet Mail Extension)用於指明內容類型。如,普通ASCII文本的MIME類型是text/plain,Web頁面的HTML源碼的MIME類型是text/html

請求動態內容:

  • Web早起,經過CGI(公共網關接口,Common Gateway Interface)與Web 服務器通訊,CGI容許單獨的進程從HTTP請求讀取數據,而後將數據寫入HTTP響應,能夠用各類語言實現CGI程序。
  • 可是CGI存在嚴重性能問題,每一個客戶端請求都須要建立獨立的進程和數據庫鏈接;並且CGI不是平臺獨立的。
  • 出現了其它技術,servlet是其中之一。
    • servlet在Web服務器地址空間內執行,不須要建立單獨進程來處理每一個客戶端請求;
    • servlet是平臺獨立的,由Java編寫;
    • 服務器上的Java安全管理器強制執行一套限制,以保護服務器上的資源;
    • servlet能夠使用Java類庫的所有功能

servelet的生命週期:

有3個方法控制servlet的生命週期:init()、service()、destroy(),每一個servlet都須要實現它們,而且特定的時間由服務器調用它們。

一個典型用戶場景:

  • 用戶在Web瀏覽器輸入URL地址
  • 瀏覽器生成HTTP請求發送到對應的服務器
  • Web服務器接收到HTTP請求
  • Web服務器將請求映射到特定的servlet
  • servlet被動態檢索並加載到服務器地址空間中
  • Web服務器調用servlet的init()方法,只有servlet第一次被加載到內存中才會調用該方法,向servlet傳遞初始化參數,以配置自身
  • Web服務器調用servlet的service()方法,以處理HTTP請求
  • servlet執行service方法時,會讀取HTTP請求中的數據,而且根據需求計算出HTTP響應
  • servlet會保留在Web服務器的地址空間中,能處理從不一樣客戶端接收到的其它HTTP請求,爲每一個請求調用service()方法
  • 最後服務器能夠決定從內存寫在servlet,調用destroy()方法,釋放資源

servlet開發選項

爲了建立servlet,須要訪問servlet容器/服務器,經常使用的有Glassfish和Tomcat

使用Tomcat開發和建立servlet:

一、安裝Tomcat

二、啓動Tomcat

三、使用Tomcat下的servlet-api.jar包,編譯寫好的servlet代碼java文件,生成class文件

四、把class文件放到Tomcat下並配置Tomcat的web.xml文件,讓Tomcat能找到這個servlet

建立並運行一個servlet:

建立並編譯servlet源碼

將servlet類文件複製到正確的目錄下,並添加servlet的名稱和映射到正確的web.xml中

啓動Tomcat

啓動Web瀏覽器,請求這個servlet

源碼編寫:

 

 

 

常見問題

JDK、JRE、JVM

JVM:java virtual machine,Java虛擬機,Java代碼編譯出來的類文件,在Java虛擬機上運行

JRE:java runtime environment,Java運行時環境,包含JVM,以及Java程序運行時須要的庫

JDK:java development kit,Java開發工具包,包括JRE,以及Java開發時須要的工具、庫等

URI、URL、URN

URI:Uniform Resource Identifier,統一資源標誌符,用來惟一的標識一個資源。

URL:Uniform Resource Locator,統一資源定位符。即URL能夠用來標識一個資源,並且還指明瞭如何locate這個資源。

URN:Uniform Resource Name,統一資源命名。即經過名字來表示資源的。

URI指一個網絡資源的標識符,有其格式;URL是URI的一種形式,包括協議、主機等信息,有其本身的格式要求;URN也是URI的一種形式,使用名稱來表示該資源。

 

 

 

實際應用

下載歷史JDK版本的方法

以前一直想下載JDK8的172版本,一直找不到下載地址

登陸甲骨文官網:https:/www.oracle.com/index.html,搜索jdk8 archive,點擊進去便可下載JDK8全部版本的存檔

 

JDK安裝

下載

下載地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html

選擇下載Java 8的JDK

根據系統選擇對應安裝包

下載後,安裝直接下一步就可

安裝完成可得2個文件夾

設置環境變量

目的有2個:一、爲了在命令行中直接能夠使用Java命令,而不須要跳轉到Java文件夾裏面才能使用;二、其它程序引用Java安裝地址時,使用這個變量便可,不須要寫絕對地址;而Java地址更改時,只要變量不變,這些程序也不須要更改地址。

一、計算機→屬性→高級系統設置→高級→環境變量→系統變量→新建 JAVA_HOME 變量,變量值填寫jdk的安裝目錄

二、系統變量→找到已存在的Path 變量→編輯→在變量值最後輸入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

此步驟至關於爲命令行增長了2個搜索java.exe程序的路徑,因此當在命令行中執行java命令時,系統就能找對java.exe程序

三、 系統變量→新建 CLASSPATH 變量→變量值填寫 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一點)

 

驗證是否安裝成功

開始→運行→輸入cmd,回車→輸入java -version

若是出現一下對應信息,表明安裝成功

JDK、JRE、JVM的區別

JDK

JDK:Java Development Kit,Java 語言軟件開發工具包。

一個工具包,能支持人類輸入編程語言,並將其轉化爲機器語言,其中包含了JRE和JVM。

JRE

JRE:Java Runtime Environment,Java運行環境。

人類使用JDK開發好程序後,JRE提供程序的運行環境,能把程序針對不一樣環境編譯成能夠運行的機器語言。JRE包含了JVM的標準實現。

JVM

JVM:Java Virtual Machine,Java虛擬機。

全部Java程序,都由JRE編譯成JVM能認識的一種特定語言,在JVM上運行,JVM再經過與不一樣操做系統,不一樣環境的交互,進而在不一樣的系統下。

2五、AWT介紹:使用窗口、圖形和文本
2六、使用AWT控件、佈局管理器和菜單
2七、圖像
2八、併發使用工具
2九、流API
30、正則表達式和其它包
3一、Swing簡介
3二、探究Swing
3三、Swing菜單簡介
3四、JavaFX GUI編程簡介誒
3五、探究JavaFX控件
3六、JavaFX菜單簡介
相關文章
相關標籤/搜索