本文篇幅較長,建議合理利用右上角目錄進行查看(若是沒有目錄請刷新)。html
目的:爲徹底瞭解Java,須要理解Java的誕生緣由、成型動力以及他繼承的思想。java
計算機語言的創新與發展的緣由:適應環境和用途的變化;實現編程藝術的完善和提升。程序員
Java大量特性從C和C++繼承過來。web
C語言前,BASIC、COBOL、FORTRAN這幾種編程語言沒有遵循結構化原則設計,依賴GOTO做爲程序控制手段;Pascal雖是結構化語言,但不是針對高效率設計的,沒法設計系統級代碼。正則表達式
C語言出現的2個條件:軟件需求加快,學術界在努力建立一種新的設計語言;計算機硬件普及,計算機再也不被鎖起來,程序員能夠隨意使用計算機進行嘗試。算法
C語言是一種功能強大、高效率、結構化的語言;並且他是程序員設計的,爲程序員服務的語言。數據庫
出現的緣由:更好地管理程序的複雜性。編程
改進:C++是在C#的基礎上,增長了對面向對象(OOP)的支持,使程序員能理解和管理更大的程序。小程序
20世紀80年代末90年代初,萬維網(World Wide Web)和因特網發展到了臨界規模。設計模式
Java於1991年,由Sun公司構想出。
最初開發Java的推進力:對平臺獨立的語言的需求。
當時須要爲一些電子設備(微波爐、遙控器等)的各類CPU開發程序,若是使用C或者C++須要對每一種CPU開發對應的編譯器,因此須要一種可移植對平臺獨立的語言。
因特網成就Java:恰好這個時候因特網的飛速發展,也須要可移植的程序,Java的特性也適合於因特網的需求,使Java的關注點從消費電子產品轉移到Internet。
一、爲了吸引C/C++的程序員,Java繼承了不少C/C++的特性,但Java不是爲了替代它們,而是爲了解決特定領域問題而出現的。
二、Java是專門針對程序員的語言,由於他的設計、測試、改進都是由程序員完成,紮根與程序員的需求,也爲程序員開放了足夠的權限。
Java影響了C#語言的發展,二者共享相同語法,支持分佈式編程,使用類似的對象模型。
Internet推進了Java,Java也影響了Internet。
Java簡化了Web編程,建立了新的網絡程序類型applet,解決了一些Internet棘手問題如移植性和安全性。
applet是一種能夠在Internet上傳送的程序,能夠在兼容Java的Web瀏覽器中自動運行。
applet擴展了網絡空間自由流動的對象的範疇。這是一種動態的,自動運行的代碼,由服務器端初始化,而後在客戶端自動運行。
雖然這種動態的聯網程序符合人們願望,可是同時帶來了嚴重的安全性和可移植性。
當下載這個自動執行的程序的時候,裏面可能包含各類病毒或者惡意代碼。
而Java將applet限定在Java的執行環境內,不容許訪問計算機的其它部分來實現安全性。
applet會被下載到不一樣的環境,不一樣的系統中,如何實如今這些不一樣的環境下的運行,下面將講解。
解決安全性和可移植性的關鍵:字節碼。
Java編譯器輸出的不是可執行代碼,而是高度優化的指令集合。
字節碼在Java運行時系統中執行,Java運行時系統也稱爲Java虛擬機(Java Virtual Machine,JVM),原始也稱爲字節碼解釋器。
Java橫跨服務器/客戶端:servlet是在服務器中執行的Java程序,像applet擴展了Web瀏覽器的功能同樣,servlet擴展了Web服務器的功能。
servlet用於動態建立發送到客戶端的內容,如servlet能夠讀取服務器數據庫,而後整理爲客戶端想要的內容,發送到客戶端;同時,servlet還提供了一些額外的優勢,例如性能的提高。
可移植性:由於servlet是Java程序,他們被編譯成字節碼,由JVM執行,因此servlet能夠用於不一樣服務器環境,只要服務器支持JVM和servlet容器。
面向對象編程(Object-Oriented Programming,OOP)在Java中處於核心地位。
全部計算機程序都包含2個元素:代碼、數據
使用抽象管理複雜性:非面向對象的編程方式,每每將對象分解爲不一樣的部分進行處理;而面向對象的編程方式,則是把對象做爲一個總體,去使用這個對象。
層次化分類:如一臺車,下面又能夠分爲駕駛系統、制動系統等,每層又能夠繼續細分。當咱們去使用這個車的對象時,則只須要了解各系統如何操做,而不須要知道這個系統裏面由什麼組成
對變化的支持:面向對象的方式猶如人類理解事物同樣;每每事物會不斷變化,例如某一部分進行改變;那麼面向對象的程序也能支持這些變化,能夠優美地廢除或者替換舊系統中的一些部分。
封裝:將代碼以及其操做的數據綁定在一齊的機制。能夠想象爲一個保護性的盒子,只容許外部經過盒子提供的通道進行訪問和操做,而不容許隨意訪問盒子裏面的代碼和數據。
封裝的基礎是類:類,是一些對象共享的一種結構和行爲(數據和代碼)。使用類建立對象,相似使用模具生產零件,這些對象也稱爲類的實例。
變量和方法:類裏面能夠定義變量和方法,稱爲成員變量(或實例變量)和成員方法(或方法)。
公有/私有:類的變量或方法能夠設置爲公有或私有,公有的表示外部用戶能夠知道的內容,私有的表示只有類的成員才能訪問。
繼承:是一個對象得到另外一個對象的屬性的過程,繼承支持了層次化分類的概念。
例如定義了一個哺乳類動物,又定義了下一層的一個類叫犬類,咱們定義犬類繼承了哺乳類,那麼就表明犬類有哺乳類的全部屬性和特徵(變量和方法)。
多態(多種形態):容許將一個接口用於一類通用動做。
多態是爲了下降複雜性。例如一個對象有同一個行爲,可是根據數據不一樣有不一樣作法的時候,使用相同的接口來指定這個行爲,而自動根據對應的參數,會執行對應的實際代碼。
經過這3個原則,能夠設計出健壯性強、方便維護、適應變化的系統級代碼。
下面例子應在安裝並配置好JDK 8下使用
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
運行後,會顯示「測試」,表明程序運行成功
Java會找到程序多個類中的main()方法啓動程序,注意大小寫,沒有找到會報錯
int num;
if(num < 100)System.out.println("yes");
用{}表示邏輯單元
if(num<100){ System.out.println("yes1"); System.out.println("yes2"); }
在編譯器完成編譯前,會檢查全部表達式和參數,確保類型是兼容的。
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不容許使用。
基本算數運算符+ - * /
注意整數類型使用除法,結果會截掉小數部分
求模運算符%
求餘數,能夠用於整數或小數
算數與賦值符合運算符+= -= *= /=
至關於運算後再賦值
自增與自減運算符++ --
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);
if(a=1){ b=1; } else if(a=2){ b=2; } else{ b=3; }
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(n>0){ System.out.println(n); n--; } i=100; j=200; while(++i<--j);//用;表示空語句
循環體至少執行一次
do{ System.out.println(n); n--; }while(n>0)
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風格在不一樣的編程語言中都有實現,是一種很受程序員喜歡的風格
在Java中,是經過for語句實現的,能夠對集合類變量進行循環
int nums[] = {1,2,3,4,5} int sum = 0; for(int x:nums){ sum+=x; }
用於終止當前所在的最近一個循環
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的循環 } }
能夠使用標籤,終止語句所在的全部嵌套循環中的其中一個
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後面的代碼將不會執行
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的一次迭代 } }
能夠使用標籤,終止語句所在的全部嵌套迭代中的其中一個
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的一次迭代 } }
顯式地從方法返回,把程序的執行控制返回到發放的調用者處
//類的基本形式 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會自動管理,大多數狀況不須要人爲編程。
爲類添加這個方法,能夠在類的對象被Java回收的時候執行方法內的代碼。
protected void finalize() { //記錄回收時間等自定義方法 }
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參數的方法 } }
能夠將對象做爲參數傳遞給方法
能夠講對象做爲參數的返回值返回
方法能夠調用本身實現遞歸算法
用於聲明類自己的成員,而不是對象的成員
限制:
一、只能直接調用其它靜態方法
二、只能直接訪問靜態數據
三、不能引用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 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(); } }
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");
限制:
一、一個方法最多隻有一個可變長度參數
二、可變長度參數必須放到最後
class VarArgs{ static void vaTest(int ... v){ for(int x : v){ System.out.println(x); } } }
一個類能夠繼承另一個類,被繼承的類叫超類,繼承別人的類叫子類
繼承:
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(); } }
用法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類型修飾符修飾的類
一、可以使用final關鍵字阻止重寫
二、可以使用final關鍵字修飾類,防止類繼承
Object類是全部其它類的超類
Object類型的引用變量能夠應用其它全部類
Object類型能夠引用數組,由於數組也是做爲類來實現的
因此全部對象均可以使用Object的方法
若是全部類都放一塊兒開發,方便易記的類名很快用完,也很容易出現協做時命名衝突的問題。
包是Java提供的一種命名機制,同時也是一種可見性控制機制。
Java使用文件系統目錄存儲包,包名必須和目錄路徑一致,包括大小寫
//定義包名,寫在Java源文件中的第一條語句 package pkg; //層次化 package java.awt.img;
Java運行時怎麼找到這些包呢?
package MyPack;
3種方式:
而對【非嵌套類】只有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); }
class Client implements Callback{ public void callback(int p){ System.out.println(p); } }
class TestIface{ public static void main(String args[]){ //使用接口調用方法 Callback c = new Client(); //調用的方法是來自對象,而不是類型變量 c.callback(42); } }
abstract class Incomplete implements Callback{ void show(){ System.out.println("Good"); } }
建立一個包含變量的接口,實現這個接口的類至關於把這些這些變量看成常量導入到類的命名控件下。
interface SharedConstants{ int NO = 0; int YES = 1; int NULL = 2; }
這種用法有爭議,僅做介紹
接口能夠繼承,實現一個子接口,必須實現這個接口的繼承鏈上全部接口的全部方法。
【JDK8】纔出現
默認方法也稱擴展方法
能夠爲接口的方法提供默認實現
動機:
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();
注意:
一、實現接口的類或子接口不會繼承接口中的靜態方法。
處理程序運行時的非正常狀態,即運行時錯誤。
Java會在出現異常時,拋出一個異常對象。
全部異常對象都是Throwable的子類
Exception:用於用戶程序應當捕獲的異常,或者自定義的異常
RuntimeException:程序自動定義
Error:通常指運行時環境出現的錯誤
若是出現異常且未捕獲,程序會終止,並輸出堆棧信息,能夠根據堆棧信息幫助查找問題。
程序處理異常,會終止程序。
咱們本身處理異常,一能夠修復錯誤,二能夠避免終止程序。
try{ do(); }catch(Exception1 e){ System.out.println(e);//輸出異常信息 catchDo(); }catch(Exception2 e){//能夠多個catch語句 catchDo(); }
顯式拋出異常
throw ThrowableInstance;
這個異常必須是Throwable或其子類類型的對象。
除了Error和RuntimeException及其子類類型的異常外,若是方法有其它類型的異常,則須要爲方法標明這些異常。
目的是讓方法的調用者知道此方法全部異常以作好準備措施。
public void do() throws MyException{ throw new MyException("test"); }
可選加載try{}catch{}後,不管是否拋出異常,都會在try{}catch{}後執行此代碼
try{ do(); }catch(Exception1 e){ System.out.println(e);//輸出異常信息 catchDo(); }finally{ finallyDo(); }
未經檢查(編譯器不檢查這些異常是否使用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個構造函數的遺留異常類設置緣由
一、帶資源的try語句
當try語句中使用資源時,再也不須要時資源能自動釋放(如文件),後面解釋
二、多重捕獲
容許同一個catch子句同時捕獲多個異常
catch(Exception1 | Exception2 e)
每一個多重捕獲參數都被隱式聲明爲final,不能從新賦值
三、最後從新拋出/更精確地從新拋出(不是很理解,暫時不理)
程序會對從新拋出的異常類型進行限制,只能從新拋出知足如下條件的經檢查的異常:由關聯的try代碼塊拋出,沒有被前面的catch子句處理過,而且是參數的子類型或超類型。
一樣catch參數隱式聲明爲final,不能從新賦值
多任務:
Java線程模型:
線程的狀態:
線程優先級:
一些整數,用於決定什麼時候從一個運行的線程切換到下一個線程,稱爲上下文切換
意思應該是這樣,根據CPU時鐘週期,空餘時間能夠用來運行線程;當線程過多,而有線程阻塞時,何時切換到下一個進程呢:
同步:
消息傳遞:
Thread類和Runable接口:
Java的多線程系統基於Thread類、Thead類的方法以及伴隨接口Runable而構建
主線程:
Java啓動就會運行一個線程,稱爲主線程。
很重要:
調用主線程
2種方法:
實現Runable接口
擴展Thread類
一樣的,擴展Thread類,重寫run()方法,而後調用start()方法類開始新線程
爲何有2種方式,哪一種好?
差異不大,一個是在於實現接口,一個是擴展重寫類。
能夠使用接口,這樣能夠使這個類能夠擴展其它類。
建立多個線程
isAlive()和join()方法
好比主線程但願等全部子線程執行完成再退出
isAlive()判斷線程是否仍在運行
可是通常經過join方法來等待線程結束
再某個線程調用其它線程的join方法,會等待該線程終止。
也能夠配置最長等待時間。
線程優先級
一、影響線程獲得CPU時間的因素:優先級、系統多任務的方式等
在搶佔式多任務環境下,高優先級的線程會替代掉低優先級的線程
在非搶佔式多任務環境下,在運行中線程正常運行狀況下(未休眠,未放棄控制權等),其它線程只有在運行中線程阻塞狀態,如I/O等待等,致使線程掛起,纔有機會運行
因此爲了平滑多個線程的執行,最好常常釋放控制權,使其它線程有機會運行。
調用setPriority方法設置線程優先級,範圍1~10,默認值5
使用Java實現可預測,跨平臺行爲的最安全方法是使用資源放棄CPU控制權的線程。
同步
當多個線程須要訪問共享資源時,他們須要用某種方法確保每次只有1個線程使用資源。
實現這個目的的過程稱爲同步。
同步使用監視器的概念實現,監視器做爲互斥鎖,一個時刻只有一個線程能夠進入監視器,而其餘試圖進入監視器的線程會被掛起,知道上一個線程退出監視器。
2種方法
使用同步方法:
Java中,全部對象都有和自身關聯的隱式監視器。要進入對象的監視器,只須要調用synchronized關鍵字修飾過的方法。
當調用對象的一個同步方法,線程就會進入對象的監視器;其它線程想要調用這個或其餘同步方法,因爲進入不了監視器,因此會被掛起等待;知道監視器種的線程退出,把對象的控制權交給下一個等待線程。
使用同步語句:
線程間通訊:
I/O:輸入輸出
流:
2種類型的流:
通常原則:在合適的狀況下,應該更新代碼,使用字符流替代字節流。
不過:在底層,全部I/O最終仍是面向字節的。
2個類層次:
InputStream和OutputStream最重要2個方法是read()和write(),子類須要實現這2個方法
2個類層次:
Reader和Writer最重要2個方法是read()和write(),子類須要實現這2個方法
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 } } }
主要是FileInputStream、FileOutputStream、AutoCloseable接口
一種Java程序,能夠在Internet服務器上訪問,傳輸,自動安裝並做爲Web文件的一部分運行的一類小程序。
transient修飾符:
volatile修飾符:
instanceof:
strictfp:
native:
assert:
import static:
this():
緊湊API配置文件:
目的:爲了解決不一樣類型的對象須要運行同一算法的需求
泛型:參數化類型,能夠使用參數指定所操做數據的類型
之前:要實現這個需求,則使用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,表明不能建立泛型異常類
JDK8新增功能
增長了新的語法元素
使API庫增長了新的功能,包括多核環境的並行處理功能(特別是for-each操做)變得容易,以及支持對數據執行管道操做的新的流API
催生了新的Java功能,包括默認方法以及方法引用
lambda表達式:
函數式接口:
()->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語句建立一個匿名實現。
方法引用:若是咱們在其餘類中,已有方法恰好實現了這個接口,那麼咱們能夠直接引用這個方法,傳入給這個函數式接口參數
原理:方法引用會建立函數式接口的一個實例。
// 靜態方法引用 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,提供了預約義的函數式接口
String、StringBuffer、StringBuilder
StringBuffer、StringBuilder用於能夠修改的字符串
StringBuilder,StringBuilder不是同步的,因此不是線程安全,優點在於性能更高
若是字符串被多個線程修改,沒有使用其它同步措施的話,須要使用StringBuffer
暫略,大部分是接口和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); } }
集合框架以前:Java提供了特定的類以存儲和管理對象組,如Dictionary、Vector、Stack和Properties。
問題:缺乏集中、統一的主體,不易擴展,不易改造。
集合框架的目標:
爲了知足這些目標,Java提供了:
新的JDK爲集合框架帶來的改變:
除了集合接口外,集合還使用Comparator、RandomAccess、Iterator以及ListIterator接口,這些後面探討。JDK8開始,還使用Spliterator接口。
Collection接口是集合框架的基礎,全部定義集合的類都必須實現這個接口,是一個泛型接口。
interface Collection<E> //E是存儲對象的類型
Collection擴展了Iterable接口,因此全部集合均可以使用for-each風格的for循環
Collection聲明瞭全部集合將擁有的核心方法
異常:
核心方法總結:添加、刪除、檢查是否包含、獲取迭代器、轉換數組、獲取流
擴展Collection,並聲明瞭用來存儲一連串元素的集合的行爲。
能夠使用從0開始的索引,經過元素位置插入或訪問元素。
能夠包含重複元素
interface List<E> //E是存儲對象的類型
Set接口定義了組,擴展了Collection接口,聲明瞭集合中不容許有重複元素的組行爲
沒有定義本身的其它方法,添加劇復元素的時候,add()方法返回false
interface Set<E> //E是存儲對象的類型
SortedSet擴展了Set接口,並聲明以升序進行排序的組行爲。
interface SortedSet<E> //E是存儲對象的類型
NavigableSet接口擴展了SortedSet接口,而且聲明瞭支持基於最接近匹配原則檢索元素的集合行爲
interface NavigableSet<E> //E是存儲對象的類型
Queue接口擴展了Collection接口,聲明瞭隊列的行爲,隊列一般是先進先出隊列,但也有其餘準則的隊列類型。
interface Queue<E> //E是存儲對象的類型
Deque接口擴展了Queue接口,而且聲明瞭雙端隊列行爲,既能夠先進先出,也能夠後進先出
interface Deque<E> //E是存儲對象的類型
集合接口的標準實現
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類擴展了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類擴展了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擴展了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擴展了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擴展了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擴展了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擴展了AbstractSet並實現了Set接口,專門用於枚舉類型的元素。
class EnumSet<E extends Enum<E>> //E是存儲對象的類型
EnumSet類沒有定義構造函數,而是使用工廠方法來建立對象
若是但願遍歷集合中的元素,方法之一是使用迭代器。
迭代器是實現了Iterator或ListIterator接口的對象。
Iterator接口容許遍歷集合,獲取或移除元素。
ListIterator接口擴展了Iterator接口,容許雙向遍歷列表,而且容許修改元素。
interface Iterator<E> //E是存儲對象的類型 interface ListIterator<E> //E是存儲對象的類型
獲取迭代器:每一個集合類都提供了iterator()方法,方法返回一個指向集合開頭的迭代器
具體步驟:
對於實現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 } }
JDK8新增一種叫splitertor的迭代器,由Spliterator接口定義。
Spliterator用於循環遍歷元素序列。
它提供的方法遠比Iterator或ListIterator多,最重要的一點是它支持並行迭代序列的一部分。
即便用不到並行編程,也能夠使用Spliterator,其中一個緣由是它把hasNext和next操做合併到一個方法中,從而提供了效率
interface Spliterator<T> //T是被迭代元素的類型
暫略,須要lambda表達式知識
RandomAccess接口不包括成員。然而經過實現這個接口,能夠代表集合支持高效地隨機訪問其中的元素。儘管集合可能支持隨機訪問,可是可能沒有這麼高效。
經過檢查RandomAccess接口,客戶端代碼能夠在運行時肯定集合是否適合特定類型的隨機訪問操做——特別是當將他們應用於大的集合時(能夠使用instance of來判斷類是否實現了這個接口)。
ArrayList和遺留的Vector類實現了RandomAccess接口。
映射是存儲鍵和值之間關係(鍵值對)的對象。
鍵和值都是對象,鍵必須惟一,但值能夠重複。
某些映射能夠接收null鍵和null值,其它不能。
映射沒有實現Iterable接口,因此不能使用for-each風格的for循環,也不能獲取迭代器。
可是能夠獲取映射的集合視圖,集合視圖容許使用for循環和迭代器。
Map接口將惟一鍵映射到值。給定鍵和值就能夠在Map對象中存儲;存儲後能夠使用鍵來檢索值。
interface Map<K,V>// K是鍵的類型,V是值的類型。
映射圍繞2個基本方法:get()、put()
使用entrySet()方法,返回一個Set對象,包含映射中元素。
使用keySet()方法,返回一個Set對象,做爲鍵的集合視圖。
使用values()方法,返回一個Set對象,做爲值的集合視圖。
修改一個集合會影響其餘集合,由於集合的數據是引用映射內的數據。
集合視圖是將映射集成到集合框架中的手段。
SortedMap接口擴展了Map接口,確保條目以鍵的升序保存。
interface SortedMap<K,V>// K爲鍵類型,V爲值類型
有序映射支持很是高效的子映射操做,如headMap()、tailMap()或subMap()方法。
NavigableMap接口擴展了SortedMap接口,支持基於最接近匹配原則的條目檢索行爲,即支持檢索與給定的一個或多個鍵最相匹配的條目。
interface NavigableMap<K,V>
Map.Entry接口提供了操做映射條目的功能。
Map接口聲明的entrySet()方法返回一個包含映射條目的Set對象。
組的全部元素都是Map.Entry對象。
interface Map.Entry<K,V>
另外JDK8添加了2個靜態方法:comparingByKey()和comparingByValue()。
前者返回根據鍵比較條目的Comparator對象,後者返回根據值比較條目的Comparator對象。
有幾個類實現了映射接口
AbstractMap是全部具體映射實現的超類。
WeakHasMap實現了使用「弱鍵」的映射,鍵不在使用時能夠被垃圾回收,這裏不討論。
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擴展了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擴展了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擴展了AbstractMap類並實現了Map接口。除了當比較元素時使用引用相等性外,其它方面和HashMap相似
class IdentityHasMap<k,V>
API文檔明確指出IdentityHashMap不用於通用目的
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類定義的每一個方法
待補充
早期的java.util包沒有包含集合框架,而是定義了幾個類和一個接口,用來提供存儲對象方法的專業方法。
注意現代集合類都不是同步的,可是全部遺留類都是同步的,固然能夠使用Collection提供的算法很容易實現同步。
包括
流的概念:流是數據的渠道。
流表明一個對象序列。
流操做數據源,如數組或集合。
流自己不存儲數據,只是移動數據,移動過程當中可能對數據執行過濾、排序或其餘操做。
通常流操做不會修改數據源,而是建立一個新的流,包含過濾、排序或其餘操做後的結果。
流接口
終端操做:會消費流,被消費後,流不能重用。
中間操做:會產生另外一個流。中間操做不是當即發生,是在新流上執行完終端操做後,中間操做纔會發生,稱爲延遲行爲,能讓流API更加高效地執行。
另外一個關鍵點:
無狀態:獨立於其餘元素處理每一個元素。如過濾,filter()
有狀態:某個元素處理以來其餘元素。如排序,sorted()
注意,並行處理流時,無狀態和有狀態區別尤爲重要,由於有狀態操做可能須要幾回處理才能完成。
Stream操做是對象引用,因此增長了如下幾個接口支持處理基本類型流,都擴展了BaseStream
DoubleStream
IntStream
LongStream
重點關注Stream,基本類型流處理上基本相同
獲取流:
一、COllection接口被擴展,包含2個獲取集合流的方法
補充代碼
縮減操做
基於任意條件,從流中返回一個值。全部縮減操做都是終端操做。
這個是Java的組件架構,經過必定的規範保證組件能夠重用和互操做;可是有Spring框架後,Spring框架中的Bean是基於POJO的,因此Java Bean的意義不大了。(我的觀點)
軟件行業一直在探索,以實現基於組件方式的可重用和互操做性。
Java Bean是一種組件架構,但願開發軟件時,能夠利用這些軟件組件來構建複雜的系統。
例如電子行業的電阻器、電容器、傳感器等。
那麼設計這能夠選擇組件,理解他們的功能,並把他們集成到應用程序中。
Java Bean:
Java語言書寫,而且遵照JavaBean API規範
軟件組件,被設計成能夠在不一樣環境下重用。
功能能夠是獲取庫存值,又或者預測股票走勢。
優點:
內省:
2種方式指示Bean應當暴露哪些屬性、事件和方法:
屬性的設計模式:
簡單屬性:
補充代碼
索引屬性:
補充代碼
事件的設計模式
補充代碼
方法與設計模式:
BeanInfo接口:
綁定屬性與約束屬性:
具備綁定屬性的Bean:
具備約束屬性的Bean:
持久性:
定製器:
Java Bean API:
Java Bean功能是由java.beans包的一組類和接口提供的。
applet動態擴展Web瀏覽器功能;而servlet是在Web鏈接的服務器端執行的小程序,動態擴展了Web服務器的功能。
背景:
Web瀏覽器如何與服務器之間進行協做並最終爲用戶提供內容呢?
請求靜態Web頁面:
請求動態內容:
servelet的生命週期:
有3個方法控制servlet的生命週期:init()、service()、destroy(),每一個servlet都須要實現它們,而且特定的時間由服務器調用它們。
一個典型用戶場景:
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
源碼編寫:
JVM:java virtual machine,Java虛擬機,Java代碼編譯出來的類文件,在Java虛擬機上運行
JRE:java runtime environment,Java運行時環境,包含JVM,以及Java程序運行時須要的庫
JDK:java development kit,Java開發工具包,包括JRE,以及Java開發時須要的工具、庫等
URI:Uniform Resource Identifier,統一資源標誌符,用來惟一的標識一個資源。
URL:Uniform Resource Locator,統一資源定位符。即URL能夠用來標識一個資源,並且還指明瞭如何locate這個資源。
URN:Uniform Resource Name,統一資源命名。即經過名字來表示資源的。
URI指一個網絡資源的標識符,有其格式;URL是URI的一種形式,包括協議、主機等信息,有其本身的格式要求;URN也是URI的一種形式,使用名稱來表示該資源。
以前一直想下載JDK8的172版本,一直找不到下載地址
登陸甲骨文官網:https:/www.oracle.com/index.html,搜索jdk8 archive,點擊進去便可下載JDK8全部版本的存檔
下載地址: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:Java Development Kit,Java 語言軟件開發工具包。
一個工具包,能支持人類輸入編程語言,並將其轉化爲機器語言,其中包含了JRE和JVM。
JRE:Java Runtime Environment,Java運行環境。
人類使用JDK開發好程序後,JRE提供程序的運行環境,能把程序針對不一樣環境編譯成能夠運行的機器語言。JRE包含了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菜單簡介 |