您好,登錄后才能下訂單哦!
這篇文章主要介紹javaSE知識點(diǎn)有哪些,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
javaSE知識點(diǎn)匯總
Java基礎(chǔ)知識精華部分
寫代碼:
1,明確需求。我要做什么?
2,分析思路。我要怎么做?1,2,3。
3,確定步驟。每一個(gè)思路部分用到哪些語句,方法,和對象。
4,代碼實(shí)現(xiàn)。用具體的java語言代碼把思路體現(xiàn)出來。
學(xué)習(xí)新技術(shù)的四點(diǎn):
1,該技術(shù)是什么?
2,該技術(shù)有什么特點(diǎn)(使用注意):
3,該技術(shù)怎么使用。demo
4,該技術(shù)什么時(shí)候用?test。
-----------------------------------------------------------------------------------------------
一:java概述:
1991 年Sun公司的James Gosling等人開始開發(fā)名稱為 Oak 的語言,希望用于控制嵌入在有線電視交換盒、PDA等的微處理器;
1994年將Oak語言更名為Java;
Java的三種技術(shù)架構(gòu):
JAVASE:Java Platform Standard Edition,完成桌面應(yīng)用程序的開發(fā),是其它兩者的基礎(chǔ);
JAVAEE:Java Platform Enterprise Edition,開發(fā)企業(yè)環(huán)境下的應(yīng)用程序,主要針對web程序開發(fā);
JAVAME:Java Platform Micro Edition,開發(fā)電子消費(fèi)產(chǎn)品和嵌入式設(shè)備,如手機(jī)中的程序;
1,JDK:Java Development Kit,java的開發(fā)和運(yùn)行環(huán)境,是java的開發(fā)工具,包括 jre。
2,JRE:Java Runtime Environment,java程序的運(yùn)行環(huán)境,java運(yùn)行的所需的類庫+JVM(java虛擬機(jī))。
3,配置環(huán)境變量:讓java jdk\bin目錄下的工具,可以在任意目錄下運(yùn)行,原因是,將該工具所在目錄告訴了系統(tǒng),當(dāng)使用該工具時(shí),由系統(tǒng)幫我們?nèi)フ抑付ǖ哪夸洝?/p>
環(huán)境變量的配置:
1):永久配置方式:JAVA_HOME=%安裝路徑%\Java\jdk
path=%JAVA_HOME%\bin
2):臨時(shí)配置方式:set path=%path%;C:\Program Files\Java\jdk\bin
特點(diǎn):系統(tǒng)默認(rèn)先去當(dāng)前路徑下找要執(zhí)行的程序,如果沒有,再去path中設(shè)置的路徑下找。
classpath的配置:
1):永久配置方式:classpath=.;c:\;e:\
2):臨時(shí)配置方式:set classpath=.;c:\;e:\
注意:在定義classpath環(huán)境變量時(shí),需要注意的情況
如果沒有定義環(huán)境變量classpath,java啟動(dòng)jvm后,會在當(dāng)前目錄下查找要運(yùn)行的類文件;
如果指定了 classpath,那么會在指定的目錄下查找要 運(yùn)行的類文件。
還會在當(dāng)前目錄找嗎?兩種情況:
1):如果classpath的值結(jié)尾處有分號,在具體路徑中沒有找到運(yùn)行的類,會默認(rèn)在當(dāng)前目錄再找一次。
2):如果classpath的值結(jié)果出沒有分號,在具體的路徑中沒有找到運(yùn)行的類,不會再當(dāng)前目錄找。
一般不指定分號,如果沒有在指定目錄下找到要運(yùn)行的類文件,就報(bào)錯(cuò),這樣可以調(diào)試程序。
4,javac命令和java命令做什么事情呢?
java是分兩部分的:一個(gè)是編譯,一個(gè)是運(yùn)行。
javac:負(fù)責(zé)的是編譯的部分,當(dāng)執(zhí)行javac時(shí),會啟動(dòng)java的編譯器程序。對指定擴(kuò)展名的.java文件進(jìn)行編譯。 生成了jvm可以識別的字節(jié)碼文件。也就是class文件,也就是java的運(yùn)行程序。
java:負(fù)責(zé)運(yùn)行的部分.會啟動(dòng)jvm.加載運(yùn)行時(shí)所需的類庫,并對class文件進(jìn)行執(zhí)行.
一個(gè)文件要被執(zhí)行,必須要有一個(gè)執(zhí)行的起始點(diǎn),這個(gè)起始點(diǎn)就是main函數(shù).
----------------------------------------------------------------------------------------------
二:java語法基礎(chǔ):
1,關(guān)鍵字:其實(shí)就是某種語言賦予了特殊含義的單詞。
保留字:其實(shí)就是還沒有賦予特殊含義,但是準(zhǔn)備日后要使用過的單詞。
2,標(biāo)示符:其實(shí)就是在程序中自定義的名詞。比如類名,變量名,函數(shù)名。包含 0-9、a-z、$、_ ;
注意:
1),數(shù)字不可以開頭。
2),不可以使用關(guān)鍵字。
3,常量:是在程序中的不會變化的數(shù)據(jù)。
4,變量:是內(nèi)存中的一個(gè)存儲空間,用于存儲 常量數(shù)據(jù)。
作用:方便于運(yùn)算。因?yàn)橛行?shù)據(jù)不確定。所以確定該數(shù)據(jù)的名詞和存儲空間。
特點(diǎn):變量空間可以重復(fù)使用。
什么時(shí)候定義變量?只要是數(shù)據(jù)不確定的時(shí)候,就定義變量。
變量空間的開辟需要什么要素呢?
1,這個(gè)空間要存儲什么數(shù)據(jù)?數(shù)據(jù)類型。
2,這個(gè)空間叫什么名字???變量名稱。
3,這個(gè)空間的第一次的數(shù)據(jù)是什么? 變量的初始化值。
變量的作用域和生存期:
變量的作用域:
作用域從變量定義的位置開始,到該變量所在的那對大括號結(jié)束;
生命周期:
變量從定義的位置開始就在內(nèi)存中活了;
變量到達(dá)它所在的作用域的時(shí)候就在內(nèi)存中消失了;
數(shù)據(jù)類型:
1):基本數(shù)據(jù)類型:整數(shù)型byte、short、int、long、浮點(diǎn)型float、double、字符型char、布爾型boolean
2):引用數(shù)據(jù)類型: 數(shù)組、類、接口。
級別從低到高為:byte,char,short(這三個(gè)平級)-->int-->float-->long-->double
自動(dòng)類型轉(zhuǎn)換:從低級別到高級別,系統(tǒng)自動(dòng)轉(zhuǎn)的;
強(qiáng)制類型轉(zhuǎn)換:什么情況下使用?把一個(gè)高級別的數(shù)賦給一個(gè)別該數(shù)的級別低的變量;
運(yùn)算符號:
1)、算術(shù)運(yùn)算符。
+ - * / % %:任何整數(shù)模2不是0就是1,所以只要改變被模數(shù)就可以實(shí)現(xiàn)開關(guān)運(yùn)算。
+:連接符。
++,--
2)、賦值運(yùn)算符。
= += -= *= /= %=
3)、比較運(yùn)算符。
特點(diǎn):該運(yùn)算符的特點(diǎn)是:運(yùn)算完的結(jié)果,要么是true,要么是false。
4)、邏輯運(yùn)算符。
& | ^ ! && ||
邏輯運(yùn)算符除了 ! 外都是用于連接兩個(gè)boolean類型表達(dá)式。
&: 只有兩邊都為true結(jié)果是true。否則就是false。
|:只要兩邊都為false結(jié)果是false,否則就是true
^:異或:和或有點(diǎn)不一樣。
兩邊結(jié)果一樣,就為false。
兩邊結(jié)果不一樣,就為true.
& 和 &&區(qū)別: & :無論左邊結(jié)果是什么,右邊都參與運(yùn)算。
&&:短路與,如果左邊為false,那么右邊不參數(shù)與運(yùn)算。
| 和|| 區(qū)別:|:兩邊都運(yùn)算。
||:短路或,如果左邊為true,那么右邊不參與運(yùn)算。
5)、位運(yùn)算符:用于操作二進(jìn)制位的運(yùn)算符。
& | ^
<< >> >>>(無符號右移)
練習(xí):對兩個(gè)變量的數(shù)據(jù)進(jìn)行互換。不需要第三方變量。
int a = 3,b = 5;-->b = 3,a = 5;
a = a + b; a = 8;
b = a - b; b = 3;c
a = a - b; a = 5;
a = a ^ b;//
b = a ^ b;//b = a ^ b ^ b = a
a = a ^ b;//a = a ^ b ^ a = b;
練習(xí):高效的算出 2*8 = 2<<3;
5,語句。
If switch do while while for
這些語句什么時(shí)候用?
1】、當(dāng)判斷固定個(gè)數(shù)的值的時(shí)候,可以使用if,也可以使用switch。
但是建議使用switch,效率相對較高。
switch(變量){
case 值:要執(zhí)行的語句;break;
…
default:要執(zhí)行的語句;
}
工作原理:用小括號中的變量的值依次和case后面的值進(jìn)行對比,
和哪個(gè)case后面的值相同了,就執(zhí)行哪個(gè)case后面的語句,如果沒有相同的則執(zhí)行default后面的語句;
細(xì)節(jié):
1):break是可以省略的,如果省略了就一直執(zhí)行到遇到break為止;
2):switch 后面的小括號中的變量應(yīng)該是byte,char,short,int四種類型中的一種;
3):default可以寫在switch結(jié)構(gòu)中的任意位置:
如果將default語句放在了第一行,則不管expression與case中的value是否匹配,程序會從default開始執(zhí)行直到第一個(gè)break出現(xiàn)。
2】、當(dāng)判斷數(shù)據(jù)范圍,獲取判斷運(yùn)算結(jié)果boolean類型時(shí),需要使用if。
3】、當(dāng)某些語句需要執(zhí)行很多次時(shí),就用循環(huán)結(jié)構(gòu)。
while和for可以進(jìn)行互換:
區(qū)別在于:如果需要定義變量控制循環(huán)次數(shù),建議使用for。因?yàn)閒or循環(huán)完畢,變量在內(nèi)存中釋放。
break:作用于switch ,和循環(huán)語句,用于跳出,或者稱為結(jié)束。
break語句單獨(dú)存在時(shí),下面不要定義其他語句,因?yàn)閳?zhí)行不到,編譯會失敗。當(dāng)循環(huán)嵌套時(shí),break只跳出當(dāng)前所在循環(huán)。要跳出嵌套中的外部循環(huán),只要給循環(huán)起名字即可,這個(gè)名字稱之為標(biāo)號。
continue:只作用于循環(huán)結(jié)構(gòu),繼續(xù)循環(huán)用的。
作用:結(jié)束本次循環(huán),繼續(xù)下次循環(huán)。該語句單獨(dú)存在時(shí),下面不可以定義語句,執(zhí)行不到。
6,函 數(shù):為了提高代碼的復(fù)用性,可以將其定義成一個(gè)單獨(dú)的功能,該功能的體現(xiàn)就是java中的函數(shù)。函數(shù)就是體現(xiàn)之一。
java中的函數(shù)的定義格式:
修飾符 返回值類型 函數(shù)名(參數(shù)類型 形式參數(shù)1,參數(shù)類型 形式參數(shù)1,…){
執(zhí)行語句;
return 返回值;
}
當(dāng)函數(shù)沒有具體的返回值時(shí),返回的返回值類型用void關(guān)鍵字表示。
如果函數(shù)的返回值類型是void時(shí),return語句可以省略不寫的,系統(tǒng)會幫你自動(dòng)加上。
return的作用:結(jié)束函數(shù)。結(jié)束功能。
如何定義一個(gè)函數(shù)?
函數(shù)其實(shí)就是一個(gè)功能,定義函數(shù)就是實(shí)現(xiàn)功能,通過兩個(gè)明確來完成:
1)、明確該功能的運(yùn)算完的結(jié)果,其實(shí)是在明確這個(gè)函數(shù)的返回值類型。
2)、在實(shí)現(xiàn)該功能的過程中是否有未知內(nèi)容參與了運(yùn)算,其實(shí)就是在明確這個(gè)函數(shù)的參數(shù)列表(參數(shù)類型&參數(shù)個(gè)數(shù))。
函數(shù)的作用:
1)、用于定義功能。
2)、用于封裝代碼提高代碼的復(fù)用性。
注意:函數(shù)中只能調(diào)用函數(shù),不能定義函數(shù)。
主函數(shù):
1)、保證該類的獨(dú)立運(yùn)行。
2)、因?yàn)樗浅绦虻娜肟凇?/p>
3)、因?yàn)樗诒籮vm調(diào)用。
函數(shù)定義名稱是為什么呢?
答:1)、為了對該功能進(jìn)行標(biāo)示,方便于調(diào)用。
2)、為了通過名稱就可以明確函數(shù)的功能,為了增加代碼的閱讀性。
重載的定義是:在一個(gè)類中,如果出現(xiàn)了兩個(gè)或者兩個(gè)以上的同名函數(shù),只要它們的參數(shù)的個(gè)數(shù),或者參數(shù)的類型不同,即可稱之為該函數(shù)重載了。
如何區(qū)分重載:當(dāng)函數(shù)同名時(shí),只看 參數(shù)列表。和返回值類型沒關(guān)系。
7,數(shù) 組:用于存儲同一類型數(shù)據(jù)的一個(gè)容器。好處:可以對該容器中的數(shù)據(jù)進(jìn)行編號,從0開始。數(shù)組用于封裝數(shù)據(jù),就是一個(gè)具體的實(shí)體。
如何在java中表現(xiàn)一個(gè)數(shù)組呢?三種表現(xiàn)形式。
1)元素類型[ ] 變量名 = new 元素類型[元素的個(gè)數(shù)];
2)元素類型[ ] 變量名 = {元素1,元素2...};
3)元素類型[ ] 變量名 = new 元素類型[ ]{元素1,元素2...};
數(shù)組定義格式詳解:
元素類型 即:數(shù)組存儲的數(shù)據(jù)類型: 創(chuàng)建的數(shù)組容器可以存儲什么數(shù)據(jù)類型。
[ ] : 表示數(shù)組。
變量名:即 數(shù)組名字:為定義的數(shù)組起個(gè)變量名,滿足標(biāo)識符規(guī)范,可以使用名字操作數(shù)組。
new:關(guān)鍵字,創(chuàng)建數(shù)組使用的關(guān)鍵字。
元素類型,即:數(shù)組存儲的數(shù)據(jù)類型: 創(chuàng)建的數(shù)組容器可以存儲什么數(shù)據(jù)類型。[長度]:數(shù)組的長度,表示數(shù)組容器中可以存儲多少個(gè)元素。
注意:數(shù)組有定長特性,長度一旦指定,不可更改
數(shù)組的訪問:
索引: 每一個(gè)存儲到數(shù)組的元素,都會自動(dòng)的擁有一個(gè)編號,從0開始,這個(gè)自動(dòng)編號稱為數(shù)組索引(index),可以通過數(shù)組的索引訪問到數(shù)組中的元素。
格式:數(shù)組名[索引]
數(shù)組的長度屬性: 獲取到數(shù)組的長度: 數(shù)組名.length 其中 屬性length的執(zhí)行結(jié)果是數(shù)組的長度,int類型結(jié)果。
數(shù)組的最大索引值為 :數(shù)組名.length-1
索引訪問數(shù)組中的元素:
1)數(shù)組名[索引]=數(shù)值,為數(shù)組中的元素賦值,如:arr[0] = 6;
2)變量=數(shù)組名[索引],獲取出數(shù)組中的元素,如:int i = arr[0]
數(shù)組作為方法參數(shù)和返回值
數(shù)組作為方法參數(shù)傳遞,傳遞的參數(shù)是數(shù)組內(nèi)存的地址
數(shù)組作為方法的返回值,返回的是數(shù)組的內(nèi)存地址
注意:方法的參數(shù)為基本類型時(shí),傳遞的是數(shù)據(jù)值. 方法的參數(shù)為引用類型時(shí),傳遞的是地址值
Arrays類:java.util.Arrays 此類包含用來操作數(shù)組的各種方法,比如排序和搜索等。其所有方法均為靜態(tài)方法
操作數(shù)組的方法
1】public static String toString(int[] a) :返回指定數(shù)組內(nèi)容的字符串表示形式
2】public static void sort(int[] a) :對指定的 int 型數(shù)組按數(shù)字升序進(jìn)行排序
1】例子:
public static void main(String[] args) {
// 定義int 數(shù)組
int[] arr = {2,34,35,4,657,8,69,9};
// 打印數(shù)組,輸出地址值
System.out.println(arr); // [I@2ac1fdc4
// 數(shù)組內(nèi)容轉(zhuǎn)為字符串
String s = Arrays.toString(arr);
// 打印字符串,輸出內(nèi)容
System.out.println(s); // [2, 34, 35, 4, 657, 8, 69, 9]
}
2】例子:
public static void main(String[] args) {
// 定義int 數(shù)組
int[] arr = {24, 7, 5, 48, 4, 46, 35, 11, 6, 2};
System.out.println("排序前:"+ Arrays.toString(arr)); // 排序前:[24, 7, 5, 48, 4, 46, 35, 11, 6,2]
// 升序排序
Arrays.sort(arr);
System.out.println("排序后:"+ Arrays.toString(arr));// 排序后:[2, 4, 5, 6, 7, 11, 24, 35, 46,48]
}
---------------------------------------------------------
//二分查找法。必須有前提:數(shù)組中的元素要有序。
public static int halfSeach_2(int[] arr,int key){
int min,max,mid;//定義最小,最大,中間數(shù)
min = 0;//最小為0
max = arr.length-1;// 最大為數(shù)組的長度-1
mid = (max+min)>>1; //(max+min)/2;//中間數(shù)為最大加最小除以2
while(arr[mid]!=key){//如果數(shù)組中間值不等于key
if(key>arr[mid]){//如果key>中間值
min = mid + 1;
}
else if(key<arr[mid])
max = mid - 1;
if(max<min)
return -1;
mid = (max+min)>>1;
}
return mid;
}
---------------------------------------------------------
Java虛擬機(jī)(jvm)的內(nèi)存劃分:
1:寄存器。2:本地方法區(qū)。3:方法區(qū)。4:棧。5:堆。
區(qū)域名稱 作用
1.寄存器 :給CPU使用,和我們開發(fā)無關(guān)。
2.本地方法棧: JVM在使用操作系統(tǒng)功能的時(shí)候使用,和我們開發(fā)無關(guān)。
3.方法區(qū) :存儲可以運(yùn)行的class文件。
4.方法棧 :方法運(yùn)行時(shí)使用的內(nèi)存,比如main方法運(yùn)行,進(jìn)入方法棧中執(zhí)行。
5.堆內(nèi)存 :存儲對象或者數(shù)組,new來創(chuàng)建的,都存儲在堆內(nèi)存。
棧:存儲的都是局部變量 ( 函數(shù)中定義的變量,函數(shù)上的參數(shù),語句中的變量 );
只要數(shù)據(jù)運(yùn)算完成所在的區(qū)域結(jié)束,該數(shù)據(jù)就會被釋放。
堆:用于存儲數(shù)組和對象,也就是實(shí)體。啥是實(shí)體???就是用于封裝多個(gè)數(shù)據(jù)的。
1:每一個(gè)實(shí)體都有內(nèi)存首地址值。
2:堆內(nèi)存中的變量都有默認(rèn)初始化值。因?yàn)閿?shù)據(jù)類型不同,值也不一樣。
3:垃圾回收機(jī)制。
---------------------------------------------------------
Math類:java.lang.Math 類包含用于執(zhí)行基本數(shù)學(xué)運(yùn)算的方法,如初等指數(shù)、對數(shù)、平方根和三角函數(shù)。
1】public static double abs(double a) :返回 double 值的絕對值 如:double d1 = Math.abs(‐5); //d1的值為5
2】public static double ceil(double a) :返回大于等于參數(shù)的最小的整數(shù)。如:double d2 = Math.ceil(‐3.3); //d2的值為 ‐3
3】public static double floor(double a) :返回小于等于參數(shù)最大的整數(shù)。如:double d2 = Math.floor(‐3.3); //d2的值為‐4.0
4】public static long round(double a) :返回最接近參數(shù)的 long。(相當(dāng)于四舍五入方法)
如:long d1 = Math.round(5.5); //d1的值為6.0
long d2 = Math.round(5.4); //d2的值為5.0
三:面向?qū)ο螅骸铩铩铩铩?/strong>
面向?qū)ο螅?/strong>強(qiáng)調(diào)的是通過調(diào)用對象的行為來實(shí)現(xiàn)功能,而不是自己一步一步的去操作實(shí)現(xiàn)
面向?qū)ο筇攸c(diǎn): 1:將復(fù)雜的事情簡單化。
2:面向?qū)ο髮⒁郧暗倪^程中的執(zhí)行者,變成了指揮者。
3:面向?qū)ο筮@種思想是符合現(xiàn)在人們思考習(xí)慣的一種思想。
面向過程和面向?qū)ο蟮膮^(qū)別:
舉例
洗衣服:
面向過程:把衣服脫下來-->找一個(gè)盆-->放點(diǎn)洗衣粉-->加點(diǎn)水-->浸泡10分鐘-->揉一揉-->清洗衣服-->擰干-->晾起來
面向?qū)ο螅喊岩路撓聛?->打開全自動(dòng)洗衣機(jī)-->扔衣服-->按鈕-->晾起來
區(qū)別:
面向過程:強(qiáng)調(diào)步驟。
面向?qū)ο螅簭?qiáng)調(diào)對象,這里的對象就是洗衣機(jī)。面向?qū)ο蟮恼Z言中,包含了三大基本特征,即封裝、繼承和多態(tài)
過程和對象 在我們的程序中是如何體現(xiàn)的呢?過程其實(shí)就是函數(shù);對象是將函數(shù)等一些內(nèi)容進(jìn)行了封裝。
匿名對象使用場景:
1:當(dāng)對方法只進(jìn)行一次調(diào)用的時(shí)候,可以使用匿名對象。
2:當(dāng)對象對成員進(jìn)行多次調(diào)用時(shí),不能使用匿名對象。必須給對象起名字。
類和對象
類:是一組相關(guān)屬性和行為的集合??梢钥闯墒且活愂挛锏哪0?,使用事物的屬性特征和行為特征來描述該類事物
屬性:就是該事物的狀態(tài)信息。行為:就是該事物能夠做什么
對象:泛指現(xiàn)實(shí)中一切事物,是一類事物的具體體現(xiàn)。對象是類的一個(gè)實(shí)例(對象并不是找個(gè)女朋友),必然具備該類事物的屬性和行為。
舉例:一只小貓。屬性:tom、5kg、2 years、yellow。 行為:溜墻根走、蹦跶的跑、喵喵叫。
類與對象的關(guān)系:
類是對一類事物的描述,是抽象的。
對象是一類事物的實(shí)例,是具體的。
類是對象的模板,對象是類的實(shí)體
類的定義:
定義類:就是定義類的成員,包括成員變量和成員方法。在定義前,必須先要對事物進(jìn)行屬性和行為的分析,才可以用代碼來體現(xiàn)。
1:成員變量:其實(shí)對應(yīng)的就是事物的屬性。在類中,方法外
2:成員函數(shù):其實(shí)對應(yīng)的就是事物的行為。只不過要把static去掉
對象的使用
對象的使用格式:創(chuàng)建對象:類名 對象名 = new 類名();
使用對象訪問類中的成員:
1)對象名.成員變量;
2)對象名.成員方法();
成員變量的默認(rèn)值
數(shù)據(jù)類型 默認(rèn)值
基本類型: 整數(shù)(byte,short,int,long) 0
浮點(diǎn)數(shù)(float,double) 0.0
字符(char) '\u0000'
布爾(boolean) false
引用類型 : 數(shù)組,類,接口 null
成員變量和局部變量的區(qū)別:
1:成員變量直接定義在類中,方法外
局部變量定義在方法中,參數(shù)上,語句中。
2:成員變量在這個(gè)類中有效。
局部變量只在自己所屬的大括號內(nèi)有效,大括號結(jié)束,局部變量失去作用域。
3:成員變量存在于堆內(nèi)存中,隨著對象的產(chǎn)生而存在,消失而消失。
局部變量存在于棧內(nèi)存中,隨著所屬區(qū)域的運(yùn)行而存在,結(jié)束而釋放。
java面向?qū)ο缶幊痰娜筇?/strong>性:封裝、繼承和多態(tài)。
面向?qū)ο蟮奶卣髦饕?封裝 繼承 多態(tài) 以及 抽象。
相關(guān)概念:
封裝:隱藏內(nèi)部實(shí)現(xiàn),提供給外界實(shí)現(xiàn)方法, 好處:不影響類內(nèi)部構(gòu)造,保護(hù)數(shù)據(jù)。是指對象把自己的數(shù)據(jù)和對數(shù)據(jù)的操作封裝在了一起;
封裝具有良好的模塊性,目標(biāo)就是實(shí)現(xiàn)編程思想中的 高內(nèi)聚,低耦合的思想(防止互相依賴帶來的變動(dòng)影響)。
在面向?qū)ο笾?,對象是封裝的基本單位,所以,在面向?qū)ο蟮恼Z言中,封裝的使用使代碼更為清晰。
在面向?qū)ο笾校庋b就是將一個(gè)對象的行為屬性封裝到一個(gè)模塊中,也就是類中,屬性用變量定義,行為用方法定義,例如 實(shí)體
封裝的回答方式從 思想 到 對象 到 如何封裝一個(gè)對象。
繼承: 兩個(gè)類具有包含關(guān)系(is-a),重用父類代碼,為多態(tài)做鋪墊。
繼承的回答方式:子類對父類的繼承,子類把父類的數(shù)據(jù)和對數(shù)據(jù)的操作繼承了過來,同時(shí)又增添了 自己的數(shù)據(jù) 和 對數(shù)據(jù)的操作;
多態(tài):主要有兩種類型的多態(tài)。一種是操作的名稱的多態(tài),即多個(gè)操作的名稱一樣,但接受的消息類型必須不同;另一種是與繼承相關(guān)的多態(tài),來自不同類型的對象對同一操作的調(diào)用產(chǎn)生不同的效果。
多態(tài)發(fā)生在代碼的運(yùn)行期。(泛型)
多態(tài)增強(qiáng)了軟件的靈活性和擴(kuò)展性(實(shí)現(xiàn)了 行為共享(方法共享))
為系統(tǒng)組件或模塊之間解耦提供了解決方案
多態(tài)的回答方式 多態(tài)的產(chǎn)生時(shí)期,和好處
實(shí)現(xiàn)多態(tài),有二種方式,覆蓋,重載。
覆蓋,是指子類重新定義父類的虛函數(shù)的做法。
重載,是指允許存在多個(gè)同名函數(shù),而這些函數(shù)的參數(shù)表不同(或許參數(shù)個(gè)數(shù)不同,或許參數(shù)類型不同,或許兩者都不同)。
函數(shù)重載:是指允許存在多個(gè)同名函數(shù),這些函數(shù)的參數(shù)列表不同,或許是參數(shù)個(gè)數(shù)不同,或許是參數(shù)類型不同,或許是兩者都不同。
重要一點(diǎn):函數(shù)重載是發(fā)生在同一個(gè)類中。調(diào)用時(shí),根據(jù)參數(shù)類型的不同進(jìn)行調(diào)用,同時(shí)編譯器在編譯期間就確定了要調(diào)用的函數(shù)。(函數(shù)的重載與多態(tài)無關(guān))。
函數(shù)覆蓋:函數(shù)覆蓋也被稱為函數(shù)重寫(override),是子類重新定義基類虛函數(shù)的方法。
構(gòu)成函數(shù)覆蓋的條件:
(1)基類的函數(shù)必須是虛函數(shù)(virtual進(jìn)行聲明)
(2)發(fā)生覆蓋的兩個(gè)函數(shù)必須分別位于派生類和基類中
(3)函數(shù)名稱和參數(shù)列表必須完全相同
由于c++,c#多態(tài)性是通過虛函數(shù)來實(shí)現(xiàn)的,所以函數(shù)覆蓋總是和多態(tài)聯(lián)系在一起,并且是程序在運(yùn)行時(shí)才確定要調(diào)用的函數(shù),因此也成為動(dòng)態(tài)綁定或者后期綁定。
函數(shù)隱藏:指子類中具有和基類同名的函數(shù),但是并不考慮參數(shù)列表是否相同,從而在子類中隱藏了基類的同名函數(shù)。有以下兩種情況:
(1)子類函數(shù)和基類函數(shù) 完全相同,只是基類的函數(shù) 沒有使用virtual關(guān)鍵字,此時(shí) 基類的函數(shù)將被隱藏。
(2)子類函數(shù)和基類函數(shù) 名字相同,但是參數(shù)列表不同,在這種情況下,無論基類的函數(shù)是否聲明為virtual,基類的函數(shù)都將被隱藏。
抽象:找出某些對象共有的一些特點(diǎn),然后歸到一個(gè)類里面,這個(gè)類的創(chuàng)建只考慮這些對象的相似之處
封裝
封 裝(面向?qū)ο筇卣髦唬菏侵鸽[藏對象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對外提供公共訪問方式。
好處:將變化隔離;便于使用;提高重用性;安全性。
1.封裝原則:將屬性隱藏起來,若需要訪問某個(gè)屬性,提供公共方法對其訪問
2.封裝的步驟
1】. 使用 private 關(guān)鍵字來修飾成員變量。
2】. 對需要訪問的成員變量,提供對應(yīng)的一對 getXxx 方法 、 setXxx 方法
3.封裝的操作——private關(guān)鍵字
private的含義
1. private是一個(gè)權(quán)限修飾符,代表最小權(quán)限。
2. 可以修飾成員變量和成員方法。
3. 被private修飾后的成員變量和成員方法,只在本類中才能訪問
private的使用格式:private 數(shù)據(jù)類型 變量名
如:private int age;//私有的訪問權(quán)限最低,只有在本類中的訪問有效。
注意:私有僅僅是封裝的一種體現(xiàn)形式而已。
私有的成員:其他類不能直接創(chuàng)建對象訪問,所以只有通過本類對外提供具體的訪問方式來完成對私有的訪問,可以通過對外提供函數(shù)的形式對其進(jìn)行訪問。
好處:可以在函數(shù)中加入邏輯判斷等操作,對數(shù)據(jù)進(jìn)行判斷等操作。
總結(jié):開發(fā)時(shí),記住,屬性是用于存儲數(shù)據(jù)的,直接被訪問,容易出現(xiàn)安全隱患,所以,類中的屬性通常被私有化,并對外提供公共的訪問方法。
這個(gè)方法一般有兩個(gè),規(guī)范寫法:對于屬性 xxx,可以使用setXXX(),getXXX()對其進(jìn)行操作
4.封裝優(yōu)化
封裝優(yōu)化51——this關(guān)鍵字
this的含義:this代表所在類的當(dāng)前對象的引用(地址值),即對象自己的引用。this:代表對象。就是所在函數(shù)所屬對象的引用。
this到底代表什么呢?哪個(gè)對象調(diào)用了this所在的函數(shù),this就代表哪個(gè)對象,就是哪個(gè)對象的引用。即誰在調(diào)用,this就代表誰。
開發(fā)時(shí),什么時(shí)候使用this呢?
在定義功能時(shí),如果該功能內(nèi)部使用到了調(diào)用該功能的對象,這時(shí)就用this來表示這個(gè)對象。
this 還可以用于構(gòu)造函數(shù)間的調(diào)用。
調(diào)用格式:this(實(shí)際參數(shù));
1】this對象后面跟上. 調(diào)用的是成員屬性和成員方法(一般方法);
this使用格式: this.成員變量 注意:方法中只有一個(gè)變量名時(shí),默認(rèn)也是使用 this 修飾,可以省略不寫
2】this對象后面跟上 () 調(diào)用的是本類中的對應(yīng)參數(shù)的構(gòu)造函數(shù)。
注意:用this調(diào)用構(gòu)造函數(shù),必須定義在構(gòu)造函數(shù)的第一行。因?yàn)闃?gòu)造函數(shù)是用于初始化的,所以初始化動(dòng)作一定要執(zhí)行。否則編譯失敗。
封裝優(yōu)化2——構(gòu)造方法
當(dāng)一個(gè)對象被創(chuàng)建時(shí)候,構(gòu)造方法用來初始化該對象,給對象的成員變量賦初始值。
注意:無論你是否自定義構(gòu)造方法,所有的類都有構(gòu)造方法,因?yàn)镴ava自動(dòng)提供了一個(gè)無參數(shù)構(gòu)造方法,一旦自己定義了構(gòu)造方法,Java自動(dòng)提供的默認(rèn)無參數(shù)構(gòu)造方法就會失效。
構(gòu)造方法的定義格式
修飾符 構(gòu)造方法名(參數(shù)列表){
// 方法體
}
構(gòu)造方法的寫法上,方法名與它所在的類名相同。它沒有返回值,所以不需要返回值類型,甚至不需要void。如:
public class Student {
private String name;private int age;
// 無參數(shù)構(gòu)造方法
public Student() {}
// 有參數(shù)構(gòu)造方法
public Student(String name,int age) {
this.name = name;
this.age = age;
}
}
注意事項(xiàng)
1. 如果你不提供構(gòu)造方法,系統(tǒng)會給出無參數(shù)構(gòu)造方法。
2. 如果你提供了構(gòu)造方法,系統(tǒng)將不再提供無參數(shù)構(gòu)造方法。
3. 構(gòu)造方法是可以重載的,既可以定義參數(shù),也可以不定義參數(shù)
5.標(biāo)準(zhǔn)代碼——JavaBean
JavaBean 是 Java語言編寫類的一種標(biāo)準(zhǔn)規(guī)范。符合 JavaBean 的類,要求類必須是具體的和公共的,并且具有無參數(shù)的構(gòu)造方法,提供用來操作成員變量的 set 和 get 方法
格式:
public class ClassName{
//成員變量
//構(gòu)造方法
//無參構(gòu)造方法【必須】
//有參構(gòu)造方法【建議】
//成員方法
//getXxx()
//setXxx()
}
繼 承(面向?qū)ο筇卣髦唬?/strong>
好處:
1:提高了代碼的復(fù)用性。
2:讓類與類之間產(chǎn)生了關(guān)系,提供了另一個(gè)特征多態(tài)的前提。
父類的由來:其實(shí)是由多個(gè)類不斷向上抽取共性內(nèi)容而來的。
java中對于繼承,java只支持單繼承。java雖然不直接支持多繼承,但是保留了這種多繼承機(jī)制,進(jìn)行改良。
單繼承:一個(gè)類只能有一個(gè)父類。
多繼承:一個(gè)類可以有多個(gè)父類。
為什么不支持多繼承呢?
因?yàn)楫?dāng)一個(gè)類同時(shí)繼承兩個(gè)父類時(shí),兩個(gè)父類中有相同的功能,那么子類對象調(diào)用該功能時(shí),運(yùn)行哪一個(gè)呢?因?yàn)楦割愔械姆椒ㄖ写嬖诜椒w。
但是java支持多重繼承。A繼承B B繼承C C繼承D。
多重繼承的出現(xiàn),就有了繼承體系。體系中的頂層父類是通過不斷向上抽取而來的。它里面定義的該體系最基本最共性內(nèi)容的功能。
所以,一個(gè)體系要想被使用,直接查閱該系統(tǒng)中的父類的功能即可知道該體系的基本用法。那么想要使用一個(gè)體系時(shí),需要建立對象。建議建立最子類對象,因?yàn)樽钭宇惒粌H可以使用父類中的功能。還可以使用子類特有的一些功能。
簡單說:對于一個(gè)繼承體系的使用,查閱頂層父類中的內(nèi)容,創(chuàng)建最底層子類的對象。
子父類出現(xiàn)后,類中的成員都有了哪些特點(diǎn):
1:成員變量。
當(dāng)子父類中出現(xiàn)一樣的屬性時(shí),子類類型的對象,調(diào)用該屬性,值是子類的屬性值。
如果想要調(diào)用父類中的屬性值,需要使用一個(gè)關(guān)鍵字:super
This:代表是本類類型的對象引用。
Super:代表是子類所屬的父類中的內(nèi)存空間引用。
注意:子父類中通常是不會出現(xiàn)同名成員變量的,因?yàn)楦割愔兄灰x了,子類就不用在定義了,直接繼承過來用就可以了。
2:成員函數(shù)。
當(dāng)子父類中出現(xiàn)了一模一樣的方法時(shí),建立子類對象會運(yùn)行子類中的方法。好像父類中的方法被覆蓋掉一樣。所以這種情況,是函數(shù)的另一個(gè)特性:覆蓋(復(fù)寫,重寫)
什么時(shí)候使用覆蓋呢?當(dāng)一個(gè)類的功能內(nèi)容需要修改時(shí),可以通過覆蓋來實(shí)現(xiàn)。
3:構(gòu)造函數(shù)。
發(fā)現(xiàn)子類構(gòu)造函數(shù)運(yùn)行時(shí),先運(yùn)行了父類的構(gòu)造函數(shù)。為什么呢?
原因:子類的所有構(gòu)造函數(shù)中的第一行,其實(shí)都有一條隱身的語句super();
super(): 表示父類的構(gòu)造函數(shù),并會調(diào)用于參數(shù)相對應(yīng)的父類中的構(gòu)造函數(shù)。而super():是在調(diào)用父類中空參數(shù)的構(gòu)造函數(shù)。
為什么子類對象初始化時(shí),都需要調(diào)用父類中的函數(shù)?(為什么要在子類構(gòu)造函數(shù)的第一行加入這個(gè)super()?)
因?yàn)樽宇惱^承父類,會繼承到父類中的數(shù)據(jù),所以必須要看父類是如何對自己的數(shù)據(jù)進(jìn)行初始化的。所以子類在進(jìn)行對象初始化時(shí),先調(diào)用父類的構(gòu)造函數(shù),這就是子類的實(shí)例化過程。
注意:子類中所有的構(gòu)造函數(shù)都會默認(rèn)訪問父類中的空參數(shù)的構(gòu)造函數(shù),因?yàn)槊恳粋€(gè)子類構(gòu)造內(nèi)第一行都有默認(rèn)的語句super();
如果父類中沒有空參數(shù)的構(gòu)造函數(shù),那么子類的構(gòu)造函數(shù)內(nèi),必須通過super語句指定要訪問的父類中的構(gòu)造函數(shù)。
如果子類構(gòu)造函數(shù)中用this來指定調(diào)用子類自己的構(gòu)造函數(shù),那么被調(diào)用的構(gòu)造函數(shù)也一樣會訪問父類中的構(gòu)造函數(shù)。
問題:super()和this()是否可以同時(shí)出現(xiàn)的構(gòu)造函數(shù)中。
兩個(gè)語句只能有一個(gè)定義在第一行,所以只能出現(xiàn)其中一個(gè)。
super()或者this():為什么一定要定義在第一行?
因?yàn)閟uper()或者this()都是調(diào)用構(gòu)造函數(shù),構(gòu)造函數(shù)用于初始化,所以初始化的動(dòng)作要先完成。
繼承的細(xì)節(jié):
什么時(shí)候使用繼承呢?
當(dāng)類與類之間存在著所屬關(guān)系時(shí),才具備了繼承的前提。a是b中的一種。a繼承b。狼是犬科中的一種。
英文書中,所屬關(guān)系:" is a "
注意:不要僅僅為了獲取其他類中的已有成員進(jìn)行繼承。
所以判斷所屬關(guān)系,可以簡單看,如果繼承后,被繼承的類中的功能,都可以被該子類所具備,那么繼承成立。如果不是,不可以繼承。
細(xì)節(jié)二:
在方法覆蓋時(shí),注意兩點(diǎn):
1:子類覆蓋父類時(shí),必須要保證,子類方法的權(quán)限必須大于等于父類方法權(quán)限可以實(shí)現(xiàn)繼承。否則,編譯失敗。
2:覆蓋時(shí),要么都靜態(tài),要么都不靜態(tài)。 (靜態(tài)只能覆蓋靜態(tài),或者被靜態(tài)覆蓋)
繼承的一個(gè)弊端:打破了封裝性。對于一些類,或者類中功能,是需要被繼承,或者復(fù)寫的。
這時(shí)如何解決問題呢?介紹一個(gè)關(guān)鍵字,final:最終。
final特點(diǎn):
1:這個(gè)關(guān)鍵字是一個(gè)修飾符,可以修飾類,方法,變量。
2:被final修飾的類是一個(gè)最終類,不可以被繼承。
3:被final修飾的方法是一個(gè)最終方法,不可以被覆蓋。
4:被final修飾的變量是一個(gè)常量,只能賦值一次。
其實(shí)這樣的原因的就是給一些固定的數(shù)據(jù)起個(gè)閱讀性較強(qiáng)的名稱。
不加final修飾不是也可以使用嗎?那么這個(gè)值是一個(gè)變量,是可以更改的。加了final,程序更為嚴(yán)謹(jǐn)。常量名稱定義時(shí),有規(guī)范,所有字母都大寫,如果由多個(gè)單詞組成,中間用 _ 連接。
抽象類: abstract
抽象:不具體,看不明白。抽象類表象體現(xiàn)。
在不斷抽取過程中,將共性內(nèi)容中的方法聲明抽取,但是方法不一樣,沒有抽取,這時(shí)抽取到的方法,并不具體,需要被指定關(guān)鍵字abstract所標(biāo)示,聲明為抽象方法。
抽象方法所在類一定要標(biāo)示為抽象類,也就是說該類需要被abstract關(guān)鍵字所修飾。
抽象類的特點(diǎn):
1:抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關(guān)鍵字修飾(可以描述類和方法,不可以描述變量)。
2:抽象方法只定義方法聲明,并不定義方法實(shí)現(xiàn)。
3:抽象類不可以被創(chuàng)建對象(實(shí)例化)。
4:只有通過子類繼承抽象類并覆蓋了抽象類中的所有抽象方法后,該子類才可以實(shí)例化。否則,該子類還是一個(gè)抽象類。
抽象類的細(xì)節(jié):
1:抽象類中是否有構(gòu)造函數(shù)?有,用于給子類對象進(jìn)行初始化。
2:抽象類中是否可以定義非抽象方法?
可以。其實(shí),抽象類和一般類沒有太大的區(qū)別,都是在描述事物,只不過抽象類在描述事物時(shí),有些功能不具體。所以抽象類和一般類在定義上,都是需要定義屬性和行為的。只不過,比一般類多了一個(gè)抽象函數(shù)。而且比一般類少了一個(gè)創(chuàng)建對象的部分。
3:抽象關(guān)鍵字abstract和哪些不可以共存?final ,private , static
4:抽象類中可不可以不定義抽象方法?可以。抽象方法目的僅僅為了不讓該類創(chuàng)建對象。
主函數(shù)和構(gòu)造函數(shù)以及一般函數(shù)
1.主函數(shù)
類中怎么沒有定義主函數(shù)呢?
注意:主函數(shù)的存在,僅為該類是否需要獨(dú)立運(yùn)行,如果不需要,主函數(shù)是不用定義的。
主函數(shù)的解釋:保證所在類的獨(dú)立運(yùn)行,是程序的入口,被jvm調(diào)用。
2.構(gòu)造函數(shù):用于給對象進(jìn)行初始化,是給與之對應(yīng)的對象進(jìn)行初始化,它具有針對性,函數(shù)中的一種。
構(gòu)造函數(shù)特點(diǎn):
1:該函數(shù)的名稱和所在類的名稱相同。
2:不需要定義返回值類型。
3:該函數(shù)沒有具體的返回值。
記?。核袑ο髣?chuàng)建時(shí),都需要初始化才可以使用。
注意事項(xiàng):一個(gè)類在定義時(shí),如果沒有定義過構(gòu)造函數(shù),那么該類中會自動(dòng)生成一個(gè)空參數(shù)的構(gòu)造函數(shù),為了方便該類創(chuàng)建對象,完成初始化。如果在類中自定義了構(gòu)造函數(shù),那么默認(rèn)的構(gòu)造函數(shù)就沒有了。
一個(gè)類中,可以有多個(gè)構(gòu)造函數(shù),因?yàn)樗鼈兊暮瘮?shù)名稱都相同,所以只能通過參數(shù)列表來區(qū)分。所以,一個(gè)類中如果出現(xiàn)多個(gè)構(gòu)造函數(shù)。它們的存在是以重載體現(xiàn)的。
構(gòu)造函數(shù)和一般函數(shù)有什么區(qū)別呢?
1:兩個(gè)函數(shù)定義格式不同。
2:構(gòu)造函數(shù)是在對象創(chuàng)建時(shí),就被調(diào)用,用于初始化,而且初始化動(dòng)作只執(zhí)行一次。
一般函數(shù),是對象創(chuàng)建后,需要調(diào)用才執(zhí)行,可以被調(diào)用多次。
什么時(shí)候使用構(gòu)造函數(shù)呢?
分析事物時(shí),發(fā)現(xiàn)具體事物一出現(xiàn),就具備了一些特征,那就將這些特征定義到構(gòu)造函數(shù)內(nèi)。
構(gòu)造代碼塊和構(gòu)造函數(shù)有什么區(qū)別?
構(gòu)造代碼塊:是給所有的對象進(jìn)行初始化,也就是說,所有的對象都會調(diào)用一個(gè)代碼塊。只要對象一建立。就會調(diào)用這個(gè)代碼塊。
構(gòu)造函數(shù):是給與之對應(yīng)的對象進(jìn)行初始化。它具有針對性。
Person p = new Person();
創(chuàng)建一個(gè)對象都在內(nèi)存中做了什么事情?
1:先將硬盤上指定位置的Person.class文件加載進(jìn)內(nèi)存。
2:執(zhí)行main方法時(shí),在棧內(nèi)存中開辟了main方法的空間(壓棧-進(jìn)棧),然后在main方法的棧區(qū)分配了一個(gè)變量p。
3:在堆內(nèi)存中開辟一個(gè)實(shí)體空間,分配了一個(gè)內(nèi)存首地址值。new
4:在該實(shí)體空間中進(jìn)行屬性的空間分配,并進(jìn)行了默認(rèn)初始化。
5:對空間中的屬性進(jìn)行顯示初始化。
6:進(jìn)行實(shí)體的構(gòu)造代碼塊初始化。
7:調(diào)用該實(shí)體對應(yīng)的構(gòu)造函數(shù),進(jìn)行構(gòu)造函數(shù)初始化。()
8:將首地址賦值給p ,p變量就引用了該實(shí)體。(指向了該對象)
--------------------------------------------------------------------------------------------
static:★★★ 關(guān)鍵字
static 關(guān)鍵字,是一個(gè)修飾符,可以修飾變量、方法和代碼塊。在使用的過程中,其主要目的還是想在不創(chuàng)建對象的情況下,去調(diào)用方法。
靜態(tài)原理
static 修飾的內(nèi)容:
是隨著類的加載而加載的,且只加載一次。
存儲于一塊固定的內(nèi)存區(qū)域(靜態(tài)區(qū)),所以,可以直接被類名調(diào)用。
它優(yōu)先于對象存在,所以,可以被所有對象共享。
1.修飾變量:
類變量:用 static關(guān)鍵字修飾的成員變量。該類的每個(gè)對象都共享同一個(gè)類變量的值。任何對象都可更改該類變量的值,但也可在不創(chuàng)建該類的對象時(shí)操作類變量
當(dāng) 用于修飾成員(成員變量和成員函數(shù))時(shí),被修飾的成員是屬于類的,而不是單單是屬于某個(gè)對象的。也就是說,既然屬于類,就可以不靠創(chuàng)建對象來調(diào)用了。
類變量 定義格式:static 數(shù)據(jù)類型 變量名
如:static int numberID;
2.修飾方法:
靜態(tài)方法
類方法:使用 static關(guān)鍵字修飾的成員方法。靜態(tài)方法在聲明中有 static ,建議使用類名來調(diào)用,而不需要
創(chuàng)建類的對象。調(diào)用方式非常簡單
定義格式:
修飾符 static 返回值類型 方法名 (參數(shù)列表){
// 執(zhí)行語句
}
靜態(tài)方法調(diào)用的注意事項(xiàng):
1】靜態(tài)方法可以直接訪問類變量和靜態(tài)方法。
2】靜態(tài)方法只能訪問靜態(tài)成員,不能直接訪問普通成員變量或成員方法。反之,成員方法可以直接訪問類變量或靜態(tài)方法。
3】靜態(tài)方法中,不能使用this關(guān)鍵字。
調(diào)用格式
被static修飾的成員可以并且建議通過類名直接訪問。雖然也可以通過對象名訪問靜態(tài)成員,原因即多個(gè)對象均屬
于一個(gè)類,共享使用同一個(gè)靜態(tài)成員,但是不建議,會出現(xiàn)警告信息。
格式:
// 訪問類變量
類名.類變量名;
// 調(diào)用靜態(tài)方法
類名.靜態(tài)方法名(參數(shù));
3.修飾代碼塊
靜態(tài)代碼塊
靜態(tài)代碼塊:定義在成員位置,使用static修飾的代碼塊{ }。
位置:類中方法外。
執(zhí)行:隨著類的加載而執(zhí)行且執(zhí)行一次,優(yōu)先于main方法和構(gòu)造方法的執(zhí)行。
作用:給類變量進(jìn)行初始化賦值。
格式:
public class ClassName{
static {
// 執(zhí)行語句
}
}
static特點(diǎn):
1,想要實(shí)現(xiàn)對象中的共性數(shù)據(jù)的對象共享??梢詫⑦@個(gè)數(shù)據(jù)進(jìn)行靜態(tài)修飾。
2,被靜態(tài)修飾的成員,可以直接被類名所調(diào)用。也就是說,靜態(tài)的成員多了一種調(diào)用方式。類名.靜態(tài)方式。
3,靜態(tài)隨著類的加載而加載。而且優(yōu)先于對象存在。
static弊端:
1,有些數(shù)據(jù)是對象特有的數(shù)據(jù),是不可以被靜態(tài)修飾的。因?yàn)槟菢拥脑?,特有?shù)據(jù)會變成對象的共享數(shù)據(jù)。這樣對事物的描述就出了問題。所以,在定義靜態(tài)時(shí),必須要明確,這個(gè)數(shù)據(jù)是否是被對象所共享的。
2,靜態(tài)方法只能訪問靜態(tài)成員,不可以訪問非靜態(tài)成員。
因?yàn)殪o態(tài)方法加載時(shí),優(yōu)先于對象存在,所以沒有辦法訪問對象中的成員。
3,靜態(tài)方法中不能使用this,super關(guān)鍵字。
因?yàn)閠his代表對象,而靜態(tài)在時(shí),有可能沒有對象,所以this無法使用。
4,主函數(shù)是靜態(tài)的。
什么時(shí)候定義靜態(tài)成員呢?或者說:定義成員時(shí),到底需不需要被靜態(tài)修飾呢?
成員分兩種:
1,成員變量。(數(shù)據(jù)共享時(shí)靜態(tài)化)
該成員變量的數(shù)據(jù)是否是所有對象都一樣:
如果是,那么該變量需要被靜態(tài)修飾,因?yàn)槭枪蚕淼臄?shù)據(jù)。
如果不是,那么就說這是對象的特有數(shù)據(jù),要存儲到對象中。
2,成員函數(shù)。(方法中沒有調(diào)用特有數(shù)據(jù)時(shí)就定義成靜態(tài))
如果判斷成員函數(shù)是否需要被靜態(tài)修飾呢?
只要參考,該函數(shù)內(nèi)是否訪問了對象中的特有數(shù)據(jù):
如果有訪問特有數(shù)據(jù),那方法不能被靜態(tài)修飾。
如果沒有訪問過特有數(shù)據(jù),那么這個(gè)方法需要被靜態(tài)修飾。
成員變量和靜態(tài)變量的區(qū)別:
1,成員變量所屬于對象。所以也稱為實(shí)例變量。
靜態(tài)變量所屬于類。所以也稱為類變量。
2,成員變量存在于堆內(nèi)存中。
靜態(tài)變量存在于方法區(qū)中。
3,成員變量隨著對象創(chuàng)建而存在。隨著對象被回收而消失。
靜態(tài)變量隨著類的加載而存在。隨著類的消失而消失。
4,成員變量只能被對象所調(diào)用 。
靜態(tài)變量可以被對象調(diào)用,也可以被類名調(diào)用。
所以,成員變量可以稱為對象的特有數(shù)據(jù),靜態(tài)變量稱為對象的共享數(shù)據(jù)。
靜態(tài)的注意:靜態(tài)的生命周期很長。
靜態(tài)代碼塊:就是一個(gè)有靜態(tài)關(guān)鍵字標(biāo)示的一個(gè)代碼塊區(qū)域。定義在類中。
作用:可以完成類的初始化。靜態(tài)代碼塊隨著類的加載而執(zhí)行,而且只執(zhí)行一次(new 多個(gè)對象就只執(zhí)行一次)。如果和主函數(shù)在同一類中,優(yōu)先于主函數(shù)執(zhí)行。
Public:訪問權(quán)限最大。
static:不需要對象,直接類名即可。
void:主函數(shù)沒有返回值。
Main:主函數(shù)特定的名稱。
(String[] args):主函數(shù)的參數(shù),是一個(gè)字符串?dāng)?shù)組類型的參數(shù),jvm調(diào)用main方法時(shí),傳遞的實(shí)際參數(shù)是 new String[0]。
jvm默認(rèn)傳遞的是長度為0的字符串?dāng)?shù)組,我們在運(yùn)行該類時(shí),也可以指定具體的參數(shù)進(jìn)行傳遞??梢栽诳刂婆_,運(yùn)行該類時(shí),在后面加入?yún)?shù)。參數(shù)之間通過空格隔開。jvm會自動(dòng)將這些字符串參數(shù)作為args數(shù)組中的元素,進(jìn)行存儲。
靜態(tài)代碼塊、構(gòu)造代碼塊、構(gòu)造函數(shù)同時(shí)存在時(shí)的執(zhí)行順序:靜態(tài)代碼塊 à 構(gòu)造代碼塊 à 構(gòu)造函數(shù);
生成Java幫助文檔:命令格式:javadoc –d 文件夾名 –auther –version *.java
/** //格式
*類描述
*@author 作者名
*@version 版本號
*/
/**
*方法描述
*@param 參數(shù)描述
*@return 返回值描述
*/
---------------------------------------------------------------------------------------------
設(shè)計(jì)模式:
設(shè)計(jì)模式:解決問題最行之有效的思想。是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。
java中有23種設(shè)計(jì)模式:
單例設(shè)計(jì)模式:★★★★★
解決的問題:保證一個(gè)類在內(nèi)存中的對象唯一性。
比如:多程序讀取一個(gè)配置文件時(shí),建議配置文件封裝成對象。會方便操作其中數(shù)據(jù),又要保證多個(gè)程序讀到的是同一個(gè)配置文件對象,就需要該配置文件對象在內(nèi)存中是唯一的。
Runtime()方法就是單例設(shè)計(jì)模式進(jìn)行設(shè)計(jì)的。
如何保證對象唯一性呢?
思想:
1,不讓其他程序創(chuàng)建該類對象。
2,在本類中創(chuàng)建一個(gè)本類對象。
3,對外提供方法,讓其他程序獲取這個(gè)對象。
步驟:
1,因?yàn)閯?chuàng)建對象都需要構(gòu)造函數(shù)初始化,只要將本類中的構(gòu)造函數(shù)私有化,其他程序就無法再創(chuàng)建該類對象;
2,就在類中創(chuàng)建一個(gè)本類的對象;
3,定義一個(gè)方法,返回該對象,讓其他程序可以通過方法就得到本類對象。(作用:可控)
代碼體現(xiàn):
1,私有化構(gòu)造函數(shù);
2,創(chuàng)建私有并靜態(tài)的本類對象;
3,定義公有并靜態(tài)的方法,返回該對象。
---------------------------------------------
//餓漢式
class Single{
private Single(){} //私有化構(gòu)造函數(shù)。
private static Single s = new Single(); //創(chuàng)建私有并靜態(tài)的本類對象。
public static Single getInstance(){ //定義公有并靜態(tài)的方法,返回該對象。
return s;
}
}
---------------------------------------------
//懶漢式:延遲加載方式。
class Single2{
private Single2(){}
private static Single2 s = null;
public static Single2 getInstance(){
if(s==null)
s = new Single2();
return s;
}
}
-------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
模板方法設(shè)計(jì)模式:
解決的問題:當(dāng)功能內(nèi)部一部分實(shí)現(xiàn)時(shí)確定,一部分實(shí)現(xiàn)是不確定的。這時(shí)可以把不確定的部分暴露出去,讓子類去實(shí)現(xiàn)。
abstract class GetTime{
public final void getTime(){ //此功能如果不需要復(fù)寫,可加final限定
long start = System.currentTimeMillis();
code(); //不確定的功能部分,提取出來,通過抽象方法實(shí)現(xiàn)
long end = System.currentTimeMillis();
System.out.println("毫秒是:"+(end-start));
}
public abstract void code(); //抽象不確定的功能,讓子類復(fù)寫實(shí)現(xiàn)
}
class SubDemo extends GetTime{
public void code(){ //子類復(fù)寫功能方法
for(int y=0; y<1000; y++){
System.out.println("y");
}
}
}
---------------------------------------------------------------------------------------------
接 口:★★★★★
1:是用關(guān)鍵字interface定義的。
2:接口中包含的成員,最常見的有全局常量、抽象方法。
注意:接口中的成員都有固定的修飾符。
成員變量:public static final
成員方法:public abstract
interface Inter{
public static final int x = 3;
public abstract void show();
}
3:接口中有抽象方法,說明接口不可以實(shí)例化。接口的子類必須實(shí)現(xiàn)了接口中所有的抽象方法后,該子類才可以實(shí)例化。否則,該子類還是一個(gè)抽象類。
4:類與類之間存在著繼承關(guān)系,類與接口中間存在的是實(shí)現(xiàn)關(guān)系。
繼承用extends ;實(shí)現(xiàn)用implements ;
5:接口和類不一樣的地方,就是,接口可以被多實(shí)現(xiàn),這就是多繼承改良后的結(jié)果。java將多繼承機(jī)制通過多現(xiàn)實(shí)來體現(xiàn)。
6:一個(gè)類在繼承另一個(gè)類的同時(shí),還可以實(shí)現(xiàn)多個(gè)接口。所以接口的出現(xiàn)避免了單繼承的局限性。還可以將類進(jìn)行功能的擴(kuò)展。
7:其實(shí)java中是有多繼承的。接口與接口之間存在著繼承關(guān)系,接口可以多繼承接口。
接口都用于設(shè)計(jì)上,設(shè)計(jì)上的特點(diǎn):(可以理解主板上提供的接口)
1:接口是對外提供的規(guī)則。
2:接口是功能的擴(kuò)展。
3:接口的出現(xiàn)降低了耦合性。
抽象類與接口:
抽象類:一般用于描述一個(gè)體系單元,將一組共性內(nèi)容進(jìn)行抽取,特點(diǎn):可以在類中定義抽象內(nèi)容讓子類實(shí)現(xiàn),可以定義非抽象內(nèi)容讓子類直接使用。它里面定義的都是一些體系中的基本內(nèi)容。
接口:一般用于定義對象的擴(kuò)展功能,是在繼承之外還需這個(gè)對象具備的一些功能。
抽象類和接口的共性:都是不斷向上抽取的結(jié)果。
抽象類和接口的區(qū)別:
1:抽象類只能被繼承,而且只能單繼承。
接口需要被實(shí)現(xiàn),而且可以多實(shí)現(xiàn)。
2:抽象類中可以定義非抽象方法,子類可以直接繼承使用。
接口中都有抽象方法,需要子類去實(shí)現(xiàn)。
3:抽象類使用的是 is a 關(guān)系。
接口使用的 like a 關(guān)系。
4:抽象類的成員修飾符可以自定義。
接口中的成員修飾符是固定的。全都是public的。
在開發(fā)之前,先定義規(guī)則,A和B分別開發(fā),A負(fù)責(zé)實(shí)現(xiàn)這個(gè)規(guī)則,B負(fù)責(zé)使用這個(gè)規(guī)則。至于A是如何對規(guī)則具體實(shí)現(xiàn)的,B是不需要知道的。這樣這個(gè)接口的出現(xiàn)就降低了A和B直接耦合性。
------------------------------------------------------------------------------------------------
多 態(tài)★★★★★(面向?qū)ο筇卣髦唬?/strong>:函數(shù)本身就具備多態(tài)性,某一種事物有不同的具體的體現(xiàn)。
體現(xiàn):父類引用或者接口的引用指向了自己的子類對象。//Animal a = new Cat();
多態(tài)的好處:提高了程序的擴(kuò)展性。
多態(tài)的弊端:當(dāng)父類引用指向子類對象時(shí),雖然提高了擴(kuò)展性,但是只能訪問父類中具備的方法,不可以訪問子類中特有的方法。(前期不能使用后期產(chǎn)生的功能,即訪問的局限性)
多態(tài)的前提:
1:必須要有關(guān)系,比如繼承、或者實(shí)現(xiàn)。
2:通常會有覆蓋操作。
多態(tài)的出現(xiàn)思想上也做著變化:以前是創(chuàng)建對象并指揮對象做事情。有了多態(tài)以后,我們可以找到對象的共性類型,直接操作共性類型做事情即可,這樣可以指揮一批對象做事情,即通過操作父類或接口實(shí)現(xiàn)。
--------------------------------------------------------------
class 畢姥爺{
void 講課(){
System.out.println("企業(yè)管理");
}
void 釣魚(){
System.out.println("釣魚");
}
}
class 畢老師 extends 畢姥爺{
void 講課(){
System.out.println("JAVA");
}
void 看電影(){
System.out.println("看電影");
}
}
class {
public static void main(String[] args) {
畢姥爺 x = new 畢老師(); //畢老師對象被提升為了畢姥爺類型。
// x.講課();
// x.看電影(); //錯(cuò)誤.
畢老師 y = (畢老師)x; //將畢姥爺類型強(qiáng)制轉(zhuǎn)換成畢老師類型。
y.看電影();//在多態(tài)中,自始自終都是子類對象在做著類型的變化。
}
}
---------------------------------------------------------------
如果想用子類對象的特有方法,如何判斷對象是哪個(gè)具體的子類類型呢?
可以可以通過一個(gè)關(guān)鍵字 instanceof ;//判斷對象是否實(shí)現(xiàn)了指定的接口或繼承了指定的類
格式:<對象 instanceof 類型> ,判斷一個(gè)對象是否所屬于指定的類型。
Student instanceof Person = true;//student繼承了person類
多態(tài)在子父類中的成員上的體現(xiàn)的特點(diǎn):
1,成員變量:在多態(tài)中,子父類成員變量同名。
在編譯時(shí)期:參考的是引用型變量所屬的類中是否有調(diào)用的成員。(編譯時(shí)不產(chǎn)生對象,只檢查語法錯(cuò)誤)
運(yùn)行時(shí)期:也是參考引用型變量所屬的類中是否有調(diào)用的成員。
簡單一句話:無論編譯和運(yùn)行,成員變量參考的都是引用變量所屬的類中的成員變量。
再說的更容易記憶一些:成員變量 --- 編譯運(yùn)行都看 = 左邊。
2,成員函數(shù)。
編譯時(shí)期:參考引用型變量所屬的類中是否有調(diào)用的方法。
運(yùn)行事情:參考的是對象所屬的類中是否有調(diào)用的方法。
為什么是這樣的呢?因?yàn)樵谧痈割愔?,對于一模一樣的成員函數(shù),有一個(gè)特性:覆蓋。
簡單一句:成員函數(shù),編譯看引用型變量所屬的類,運(yùn)行看對象所屬的類。
更簡單:成員函數(shù) --- 編譯看 = 左邊,運(yùn)行看 = 右邊。
3,靜態(tài)函數(shù)。
編譯時(shí)期:參考的是引用型變量所屬的類中是否有調(diào)用的成員。
運(yùn)行時(shí)期:也是參考引用型變量所屬的類中是否有調(diào)用的成員。
為什么是這樣的呢?因?yàn)殪o態(tài)方法,其實(shí)不所屬于對象,而是所屬于該方法所在的類。
調(diào)用靜態(tài)的方法引用是哪個(gè)類的引用調(diào)用的就是哪個(gè)類中的靜態(tài)方法。
簡單說:靜態(tài)函數(shù) --- 編譯運(yùn)行都看 = 左邊。
-----------------------------------------------------------------------------------------------
------java.lang.Object
Object:所有類的直接或者間接父類,Java認(rèn)為所有的對象都具備一些基本的共性內(nèi)容,這些內(nèi)容可以不斷的向上抽取,最終就抽取到了一個(gè)最頂層的類中的,該類中定義的就是所有對象都具備的功能。
具體方法:
1,boolean equals(Object obj):用于比較兩個(gè)對象是否相等,其實(shí)內(nèi)部比較的就是兩個(gè)對象地址。
而根據(jù)對象的屬性不同,判斷對象是否相同的具體內(nèi)容也不一樣。所以在定義類時(shí),一般都會復(fù)寫equals方法,建立本類特有的判斷對象是否相同的依據(jù)。ooo
public boolean equals(Object obj){
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.age == p.age;
}
2,String toString():將對象變成字符串;默認(rèn)返回的格式:類名@哈希值 = getClass().getName() + '@' + Integer.toHexString(hashCode())
為了對象對應(yīng)的字符串內(nèi)容有意義,可以通過復(fù)寫,建立該類對象自己特有的字符串表現(xiàn)形式。
public String toString(){
return "person : "+age;
}
3,Class getClass():獲取任意對象運(yùn)行時(shí)的所屬字節(jié)碼文件對象。
4,int hashCode():返回該對象的哈希碼值。支持此方法是為了提高哈希表的性能。
通常equals,toString,hashCode,在應(yīng)用中都會被復(fù)寫,建立具體對象的特有的內(nèi)容。
------------------------------------------------------------------------------------------------
內(nèi)部類:如果A類需要直接訪問B類中的成員,而B類又需要建立A類的對象。這時(shí),為了方便設(shè)計(jì)和訪問,直接將A類定義在B類中。就可以了。A類就稱為內(nèi)部類。內(nèi)部類可以直接訪問外部類中的成員。而外部類想要訪問內(nèi)部類,必須要建立內(nèi)部類的對象。
-----------------------------------------------------
class Outer{
int num = 4;
class Inner {
void show(){
System.out.println("inner show run "+num);
}
}
public void method(){
Inner in = new Inner();//創(chuàng)建內(nèi)部類的對象。
in.show();//調(diào)用內(nèi)部類的方法。
}
}
-------------------------------------------------------
當(dāng)內(nèi)部類定義在外部類中的成員位置上,可以使用一些成員修飾符修飾 private、static。
1:默認(rèn)修飾符。
直接訪問內(nèi)部類格式:外部類名.內(nèi)部類名 變量名 = 外部類對象.內(nèi)部類對象;
Outer.Inner in = new Outer.new Inner();//這種形式很少用。
但是這種應(yīng)用不多見,因?yàn)閮?nèi)部類之所以定義在內(nèi)部就是為了封裝。想要獲取內(nèi)部類對象通常都通過外部類的方法來獲取。這樣可以對內(nèi)部類對象進(jìn)行控制。
2:私有修飾符。
通常內(nèi)部類被封裝,都會被私有化,因?yàn)榉庋b性不讓其他程序直接訪問。
3:靜態(tài)修飾符。
如果內(nèi)部類被靜態(tài)修飾,相當(dāng)于外部類,會出現(xiàn)訪問局限性,只能訪問外部類中的靜態(tài)成員。
注意;如果內(nèi)部類中定義了靜態(tài)成員,那么該內(nèi)部類必須是靜態(tài)的。
內(nèi)部類編譯后的文件名為:“外部類名$內(nèi)部類名.java”;
為什么內(nèi)部類可以直接訪問外部類中的成員呢?
那是因?yàn)閮?nèi)部中都持有一個(gè)外部類的引用。這個(gè)是引用是 外部類名.this
內(nèi)部類可以定義在外部類中的成員位置上,也可以定義在外部類中的局部位置上。
當(dāng)內(nèi)部類被定義在局部位置上,只能訪問局部中被final修飾的局部變量。
匿名內(nèi)部類:沒有名字的內(nèi)部類。就是內(nèi)部類的簡化形式。一般只用一次就可以用這種形式。匿名內(nèi)部類其實(shí)就是一個(gè)匿名子類對象。想要定義匿名內(nèi)部類:需要前提,內(nèi)部類必須繼承一個(gè)類或者實(shí)現(xiàn)接口。
匿名內(nèi)部類的格式:new 父類名&接口名(){ 定義子類成員或者覆蓋父類方法 }.方法。
匿名內(nèi)部類的使用場景:
當(dāng)函數(shù)的參數(shù)是接口類型引用時(shí),如果接口中的方法不超過3個(gè)??梢酝ㄟ^匿名內(nèi)部類來完成參數(shù)的傳遞。
其實(shí)就是在創(chuàng)建匿名內(nèi)部類時(shí),該類中的封裝的方法不要過多,最好兩個(gè)或者兩個(gè)以內(nèi)。
--------------------------------------------------------
//面試
//1
new Object(){
void show(){
System.out.println("show run");
}
}.show();
//2
Object obj = new Object(){
void show(){
System.out.println("show run");
}
};
obj.show();
1和2的寫法正確嗎?有區(qū)別嗎?說出原因。
寫法是正確,1和2都是在通過匿名內(nèi)部類建立一個(gè)Object類的子類對象。
區(qū)別:
第一個(gè)可是編譯通過,并運(yùn)行。
第二個(gè)編譯失敗,因?yàn)槟涿麅?nèi)部類是一個(gè)子類對象,當(dāng)用Object的obj引用指向時(shí),就被提升為了
Object類型,而編譯時(shí)檢查Object類中是否有show方法,所以編譯失敗。
-------------------------------------------------------
class InnerClassDemo6 {
+(static)class Inner{
void show(){}
}
public void method(){
this.new Inner().show();//可以
}
public static void main(String[] args) {//static不允許this
This.new Inner().show();//錯(cuò)誤,Inner類需要定義成static
}
}
------------------------------------------------------
interface Inter{
void show();
}
class Outer{//通過匿名內(nèi)部類補(bǔ)足Outer類中的代碼。
public static Inter method(){
return new Inter(){
public void show(){}
};
}
}
class InnerClassDemo7 {
public static void main(String[] args) {
Outer.method().show();
/*
Outer.method():意思是:Outer中有一個(gè)名稱為method的方法,而且這個(gè)方法是靜態(tài)的。
Outer.method().show():當(dāng)Outer類調(diào)用靜態(tài)的method方法運(yùn)算結(jié)束后的結(jié)果又調(diào)用了show方法,意味著:method()方法運(yùn)算完一個(gè)是對象,而且這個(gè)對象是Inter類型的。
*/
function (new Inter(){
public void show(){}
}); //匿名內(nèi)部類作為方法的參數(shù)進(jìn)行傳遞。
}
public static void function(Inter in){
in.show();
}
}
------------------------------------------------------------------------------------------------
異 常:★★★★
異常:就是不正常。程序在運(yùn)行時(shí)出現(xiàn)的不正常情況。其實(shí)就是程序中出現(xiàn)的問題。這個(gè)問題按照面向?qū)ο笏枷脒M(jìn)行描述,并封裝成了對象。因?yàn)閱栴}的產(chǎn)生有產(chǎn)生的原因、有問題的名稱、有問題的描述等多個(gè)屬性信息存在。當(dāng)出現(xiàn)多屬性信息最方便的方式就是將這些信息進(jìn)行封裝。異常就是java按照面向?qū)ο蟮乃枷雽栴}進(jìn)行對象封裝。這樣就方便于操作問題以及處理問題。
出現(xiàn)的問題有很多種,比如角標(biāo)越界,空指針等都是。就對這些問題進(jìn)行分類。而且這些問題都有共性內(nèi)容比如:每一個(gè)問題都有名稱,同時(shí)還有問題描述的信息,問題出現(xiàn)的位置,所以可以不斷的向上抽取。形成了異常體系。
--------java.lang.Throwable:
Throwable:可拋出的。
|--Error:錯(cuò)誤,一般情況下,不編寫針對性的代碼進(jìn)行處理,通常是jvm發(fā)生的,需要對程序進(jìn)行修正。
|--Exception:異常,可以有針對性的處理方式
無論是錯(cuò)誤還是異常,它們都有具體的子類體現(xiàn)每一個(gè)問題,它們的子類都有一個(gè)共性,就是都以父類名才作為子類的后綴名。
這個(gè)體系中的所有類和對象都具備一個(gè)獨(dú)有的特點(diǎn);就是可拋性。
可拋性的體現(xiàn):就是這個(gè)體系中的類和對象都可以被throws和throw兩個(gè)關(guān)鍵字所操作。
------------------------------------------------------
class ExceptionDemo{
public static void main(String[] args) {
// byte[] buf = new byte[1024*1024*700];//java.lang.OutOfMemoryError內(nèi)存溢出錯(cuò)誤
}
}
------------------------------------------------------
在開發(fā)時(shí),如果定義功能時(shí),發(fā)現(xiàn)該功能會出現(xiàn)一些問題,應(yīng)該將問題在定義功能時(shí)標(biāo)示出來,這樣調(diào)用者就可以在使用這個(gè)功能的時(shí)候,預(yù)先給出處理方式。
如何標(biāo)示呢?通過throws關(guān)鍵字完成,格式:throws 異常類名,異常類名...
這樣標(biāo)示后,調(diào)用者,在使用該功能時(shí),就必須要處理,否則編譯失敗。
處理方式有兩種:1、捕捉;2、拋出。
對于捕捉:java有針對性的語句塊進(jìn)行處理。
try {
需要被檢測的代碼;
}
catch(異常類 變量名){
異常處理代碼;
}
fianlly{
一定會執(zhí)行的代碼;
}
--------------------------------------------------------
catch (Exception e) { //e用于接收try檢測到的異常對象。
System.out.println("message:"+e.getMessage());//獲取的是異常的信息。
System.out.println("toString:"+e.toString());//獲取的是異常的名字+異常的信息。
e.printStackTrace();//打印異常在堆棧中信息;異常名稱+異常信息+異常的位置。
}
---------------------------------------------------------
異常處理原則:功能拋出幾個(gè)異常,功能調(diào)用如果進(jìn)行try處理,需要與之對應(yīng)的catch處理代碼塊,這樣的處理有針對性,拋幾個(gè)就處理幾個(gè)。
特殊情況:try對應(yīng)多個(gè)catch時(shí),如果有父類的catch語句塊,一定要放在下面。
throw 和throws關(guān)鍵字的區(qū)別:
throw用于拋出異常對象,后面跟的是異常對象;throw用在函數(shù)內(nèi)。
throws用于拋出異常類,后面跟的異常類名,可以跟多個(gè),用逗號隔開。throws用在函數(shù)上。
通常情況:函數(shù)內(nèi)容如果有throw,拋出異常對象,并沒有進(jìn)行處理,那么函數(shù)上一定要聲明,否則編譯失敗。但是也有特殊情況。
異常分兩種:
1:編譯時(shí)被檢查的異常,只要是Exception及其子類都是編譯時(shí)被檢測的異常。
2:運(yùn)行時(shí)異常,其中Exception有一個(gè)特殊的子類RuntimeException,以及RuntimeException的子類是運(yùn)行異常,也就說這個(gè)異常是編譯時(shí)不被檢查的異常。
編譯時(shí)被檢查的異常和運(yùn)行時(shí)異常的區(qū)別:
編譯被檢查的異常在函數(shù)內(nèi)被拋出,函數(shù)必須要聲明,否編譯失敗。
聲明的原因:是需要調(diào)用者對該異常進(jìn)行處理。
運(yùn)行時(shí)異常如果在函數(shù)內(nèi)被拋出,在函數(shù)上不需要聲明。
不聲明的原因:不需要調(diào)用者處理,運(yùn)行時(shí)異常發(fā)生,已經(jīng)無法再讓程序繼續(xù)運(yùn)行,所以,不讓調(diào)用處理的,直接讓程序停止,由調(diào)用者對代碼進(jìn)行修正。
定義異常處理時(shí),什么時(shí)候定義try,什么時(shí)候定義throws呢?
功能內(nèi)部如果出現(xiàn)異常,如果內(nèi)部可以處理,就用try;
如果功能內(nèi)部處理不了,就必須聲明出來,讓調(diào)用者處理。
自定義異常:當(dāng)開發(fā)時(shí),項(xiàng)目中出現(xiàn)了java中沒有定義過的問題時(shí),這時(shí)就需要我們按照java異常建立思想,將項(xiàng)目的中的特有問題也進(jìn)行對象的封裝。這個(gè)異常,稱為自定義異常。
對于除法運(yùn)算,0作為除數(shù)是不可以的。java中對這種問題用ArithmeticException類進(jìn)行描述。對于這個(gè)功能,在我們項(xiàng)目中,除數(shù)除了不可以為0外,還不可以為負(fù)數(shù)??墒秦?fù)數(shù)的部分java并沒有針對描述。所以我們就需要自定義這個(gè)異常。
自定義異常的步驟:
1:定義一個(gè)子類繼承Exception或RuntimeException,讓該類具備可拋性。
2:通過throw 或者throws進(jìn)行操作。
異常的轉(zhuǎn)換思想:當(dāng)出現(xiàn)的異常是調(diào)用者處理不了的,就需要將此異常轉(zhuǎn)換為一個(gè)調(diào)用者可以處理的異常拋出。
try catch finally的幾種結(jié)合方式:
1,
try
catch
finally
這種情況,如果出現(xiàn)異常,并不處理,但是資源一定關(guān)閉,所以try finally集合只為關(guān)閉資源。
記?。?/strong>finally很有用,主要用戶關(guān)閉資源。無論是否發(fā)生異常,資源都必須進(jìn)行關(guān)閉。
System.exit(0); //退出jvm,只有這種情況finally不執(zhí)行。
當(dāng)異常出現(xiàn)后,在子父類進(jìn)行覆蓋時(shí),有了一些新的特點(diǎn):
1:當(dāng)子類覆蓋父類的方法時(shí),如果父類的方法拋出了異常,那么子類的方法要么不拋出異常要么拋出父類異常或者該異常的子類,不能拋出其他異常。
2:如果父類拋出了多個(gè)異常,那么子類在覆蓋時(shí)只能拋出父類的異常的子集。
注意:
如果父類或者接口中的方法沒有拋出過異常,那么子類是不可以拋出異常的,如果子類的覆蓋的方法中出現(xiàn)了異常,只能try不能throws。
如果這個(gè)異常子類無法處理,已經(jīng)影響了子類方法的具體運(yùn)算,這時(shí)可以在子類方法中,通過throw拋出RuntimeException異?;蛘咂渥宇悾@樣,子類的方法上是不需要throws聲明的。
常見異常:
1、腳標(biāo)越界異常(IndexOutOfBoundsException)包括數(shù)組、字符串;
空指針異常(NullPointerException)
2、類型轉(zhuǎn)換異常:ClassCastException
3、沒有這個(gè)元素異常:NullPointerException
4、不支持操作異常;
異常要盡量避免,如果避免不了,需要預(yù)先給出處理方式。比如家庭備藥,比如滅火器。
-----------------------------------------------------------------------------------------------
包:定義包用package關(guān)鍵字。
1:對類文件進(jìn)行分類管理。
2:給類文件提供多層名稱空間。
如果生成的包不在當(dāng)前目錄下,需要最好執(zhí)行classpath,將包所在父目錄定義到classpath變量中即可。
一般在定義包名時(shí),因?yàn)榘某霈F(xiàn)是為了區(qū)分重名的類。所以包名要盡量唯一。怎么保證唯一性呢?可以使用url域名來進(jìn)行包名稱的定義。
package pack;//定義了一個(gè)包,名稱為pack。 注意:包名的寫法規(guī)范:所有字母都小寫。
//package cn.itcast.pack.demo;
類的全名稱是 包名.類名
編譯命令:javac –d 位置(.當(dāng)前路徑) java源文件 (就可以自動(dòng)生成包)
包是一種封裝形式,用于封裝類,想要被包以外的程序訪問,該類必須public;
類中的成員,如果被包以外訪問,也必須public;
包與包之間訪問可以使用的權(quán)限有兩種:
1:public
2:protected:只能是不同包中的子類可以使用的權(quán)限。
總結(jié)java中的四種權(quán)限:
范圍 publicprotected(保護(hù)) default(默認(rèn))private
同一個(gè)類中 ok ok ok ok
同一包中 ok ok ok
子類 ok
不同包中 ok ok
-----------------------------------------------------------------------------------------------
Import - 導(dǎo)入:類名稱變長,寫起來很麻煩。為了簡化,使用了一個(gè)關(guān)鍵字:import,可以使用這個(gè)關(guān)鍵字導(dǎo)入指定包中的類。記住:實(shí)際開發(fā)時(shí),到的哪個(gè)類就導(dǎo)入哪個(gè)類,不建議使用*.
import packa.*;//這個(gè)僅僅是導(dǎo)入了packa當(dāng)前目錄下的所有的類。不包含子包。
import packa.abc.*;//導(dǎo)入了packa包中的子包abc下的當(dāng)前的所有類。
如果導(dǎo)入的兩個(gè)包中存在著相同名稱的類。這時(shí)如果用到該類,必須在代碼中指定包名。
常見的軟件包:
java.lang : language java的核心包,Object System String Throwable jdk1.2版本后,該包中的類自動(dòng)被導(dǎo)入。
java.awt : 定義的都是用于java圖形界面開發(fā)的對象。
javax.swing: 提供所有的windows桌面應(yīng)用程序包括的控件,比如:Frame , Dialog, Table, List 等等,就是java的圖形界面庫。
java.net : 用于java網(wǎng)絡(luò)編程方面的對象都在該包中。
java.io : input output 用于操作設(shè)備上數(shù)據(jù)的對象都在該包中。比如:讀取硬盤數(shù)據(jù),往硬盤寫入數(shù)據(jù)。
java.util : java的工具包,時(shí)間對象,集合框架。
java.applet: application+let 客戶端java小程序。server+let --> servlet 服務(wù)端java小程序。
jar :java的壓縮包,主要用于存儲類文件,或者配置文件等。
命令格式:jar –cf 包名.jar 包目錄
解壓縮:jar –xvf 包名.jar
將jar包目錄列表重定向到一個(gè)文件中:jar –tf 包名.jar >c:\1.txt
-----------------------------------------------------------------------------------------------
多線程:★★★★
進(jìn)程:正在進(jìn)行中的程序。其實(shí)進(jìn)程就是一個(gè)應(yīng)用程序運(yùn)行時(shí)的內(nèi)存分配空間。
線程:其實(shí)就是進(jìn)程中一個(gè)程序執(zhí)行控制單元,一條執(zhí)行路徑。進(jìn)程負(fù)責(zé)的是應(yīng)用程序的空間的標(biāo)示。線程負(fù)責(zé)的是應(yīng)用程序的執(zhí)行順序。
一個(gè)進(jìn)程至少有一個(gè)線程在運(yùn)行,當(dāng)一個(gè)進(jìn)程中出現(xiàn)多個(gè)線程時(shí),就稱這個(gè)應(yīng)用程序是多線程應(yīng)用程序,每個(gè)線程在棧區(qū)中都有自己的執(zhí)行空間,自己的方法區(qū)、自己的變量。
jvm在啟動(dòng)的時(shí),首先有一個(gè)主線程,負(fù)責(zé)程序的執(zhí)行,調(diào)用的是main函數(shù)。主線程執(zhí)行的代碼都在main方法中。
當(dāng)產(chǎn)生垃圾時(shí),收垃圾的動(dòng)作,是不需要主線程來完成,因?yàn)檫@樣,會出現(xiàn)主線程中的代碼執(zhí)行會停止,會去運(yùn)行垃圾回收器代碼,效率較低,所以由單獨(dú)一個(gè)線程來負(fù)責(zé)垃圾回收。
隨機(jī)性的原理:因?yàn)閏pu的快速切換造成,哪個(gè)線程獲取到了cpu的執(zhí)行權(quán),哪個(gè)線程就執(zhí)行。
返回當(dāng)前線程的名稱:Thread.currentThread().getName()
線程的名稱是由:Thread-編號定義的。編號從0開始。
線程要運(yùn)行的代碼都統(tǒng)一存放在了run方法中。
線程要運(yùn)行必須要通過類中指定的方法開啟。start方法。(啟動(dòng)后,就多了一條執(zhí)行路徑)
start方法:1)、啟動(dòng)了線程;2)、讓jvm調(diào)用了run方法。
創(chuàng)建線程的第一種方式:繼承Thread ,由子類復(fù)寫run方法。
步驟:
1,定義類繼承Thread類;
2,目的是復(fù)寫run方法,將要讓線程運(yùn)行的代碼都存儲到run方法中;
3,通過創(chuàng)建Thread類的子類對象,創(chuàng)建線程對象;
4,調(diào)用線程的start方法,開啟線程,并執(zhí)行run方法。
線程狀態(tài):
被創(chuàng)建:start()
運(yùn)行:具備執(zhí)行資格,同時(shí)具備執(zhí)行權(quán);
凍結(jié):sleep(time),wait()—notify()喚醒;線程釋放了執(zhí)行權(quán),同時(shí)釋放執(zhí)行資格;
臨時(shí)阻塞狀態(tài):線程具備cpu的執(zhí)行資格,沒有cpu的執(zhí)行權(quán);
消亡:stop()
創(chuàng)建線程的第二種方式:實(shí)現(xiàn)一個(gè)接口Runnable。
步驟:
1,定義類實(shí)現(xiàn)Runnable接口。
2,覆蓋接口中的run方法(用于封裝線程要運(yùn)行的代碼)。
3,通過Thread類創(chuàng)建線程對象;
4,將實(shí)現(xiàn)了Runnable接口的子類對象作為實(shí)際參數(shù)傳遞給Thread類中的構(gòu)造函數(shù)。
為什么要傳遞呢?因?yàn)橐尵€程對象明確要運(yùn)行的run方法所屬的對象。
5,調(diào)用Thread對象的start方法。開啟線程,并運(yùn)行Runnable接口子類中的run方法。
Ticket t = new Ticket();
/*
直接創(chuàng)建Ticket對象,并不是創(chuàng)建線程對象。
因?yàn)閯?chuàng)建對象只能通過new Thread類,或者new Thread類的子類才可以。
所以最終想要?jiǎng)?chuàng)建線程。既然沒有了Thread類的子類,就只能用Thread類。
*/
Thread t1 = new Thread(t); //創(chuàng)建線程。
/*
只要將t作為Thread類的構(gòu)造函數(shù)的實(shí)際參數(shù)傳入即可完成線程對象和t之間的關(guān)聯(lián)
為什么要將t傳給Thread類的構(gòu)造函數(shù)呢?其實(shí)就是為了明確線程要運(yùn)行的代碼run方法。
*/
t1.start();
為什么要有Runnable接口的出現(xiàn)?
1:通過繼承Thread類的方式,可以完成多線程的建立。但是這種方式有一個(gè)局限性,如果一個(gè)類已經(jīng)有了自己的父類,就不可以繼承Thread類,因?yàn)閖ava單繼承的局限性。
可是該類中的還有部分代碼需要被多個(gè)線程同時(shí)執(zhí)行。這時(shí)怎么辦呢?
只有對該類進(jìn)行額外的功能擴(kuò)展,java就提供了一個(gè)接口Runnable。這個(gè)接口中定義了run方法,其實(shí)run方法的定義就是為了存儲多線程要運(yùn)行的代碼。
所以,通常創(chuàng)建線程都用第二種方式。
因?yàn)閷?shí)現(xiàn)Runnable接口可以避免單繼承的局限性。
2:其實(shí)是將不同類中需要被多線程執(zhí)行的代碼進(jìn)行抽取。將多線程要運(yùn)行的代碼的位置單獨(dú)定義到接口中。為其他類進(jìn)行功能擴(kuò)展提供了前提。
所以Thread類在描述線程時(shí),內(nèi)部定義的run方法,也來自于Runnable接口。
實(shí)現(xiàn)Runnable接口可以避免單繼承的局限性。而且,繼承Thread,是可以對Thread類中的方法,進(jìn)行子類復(fù)寫的。但是不需要做這個(gè)復(fù)寫動(dòng)作的話,只為定義線程代碼存放位置,實(shí)現(xiàn)Runnable接口更方便一些。所以Runnable接口將線程要執(zhí)行的任務(wù)封裝成了對象。
-------------------------------------------------------
//面試
new Thread(new Runnable(){ //匿名
public void run(){
System.out.println("runnable run");
}
}
{
public void run(){
System.out.println("subthread run");
}
}.start(); //結(jié)果:subthread run
---------------------------------------------------------
Try {
Thread.sleep(10);
}catch(InterruptedException e){}// 當(dāng)刻意讓線程稍微停一下,模擬cpu 切換情況。
多線程安全問題的原因:
通過圖解:發(fā)現(xiàn)一個(gè)線程在執(zhí)行多條語句時(shí),并運(yùn)算同一個(gè)數(shù)據(jù)時(shí),在執(zhí)行過程中,其他線程參與進(jìn)來,并操作了這個(gè)數(shù)據(jù)。導(dǎo)致到了錯(cuò)誤數(shù)據(jù)的產(chǎn)生。
涉及到兩個(gè)因素:
1,多個(gè)線程在操作共享數(shù)據(jù)。
2,有多條語句對共享數(shù)據(jù)進(jìn)行運(yùn)算。
原因:這多條語句,在某一個(gè)時(shí)刻被一個(gè)線程執(zhí)行時(shí),還沒有執(zhí)行完,就被其他線程執(zhí)行了。
解決安全問題的原理:
只要將操作共享數(shù)據(jù)的語句在某一時(shí)段讓一個(gè)線程執(zhí)行完,在執(zhí)行過程中,其他線程不能進(jìn)來執(zhí)行就可以解決這個(gè)問題。
如何進(jìn)行多句操作共享數(shù)據(jù)代碼的封裝呢?
java中提供了一個(gè)解決方式:就是同步代碼塊。
格式:
synchronized(對象) { // 任意對象都可以。這個(gè)對象就是鎖。
需要被同步的代碼;
}
---------------------------------------------------------------
同步:★★★★★
好處:解決了線程安全問題。
弊端:相對降低性能,因?yàn)榕袛噫i需要消耗資源,產(chǎn)生了死鎖。
定義同步是有前提的:
1,必須要有兩個(gè)或者兩個(gè)以上的線程,才需要同步。
2,多個(gè)線程必須保證使用的是同一個(gè)鎖。
同步的第二種表現(xiàn)形式:
同步函數(shù):其實(shí)就是將同步關(guān)鍵字定義在函數(shù)上,讓函數(shù)具備了同步性。
同步函數(shù)是用的哪個(gè)鎖呢?
通過驗(yàn)證,函數(shù)都有自己所屬的對象this,所以同步函數(shù)所使用的鎖就是this鎖。
當(dāng)同步函數(shù)被static修飾時(shí),這時(shí)的同步用的是哪個(gè)鎖呢?
靜態(tài)函數(shù)在加載時(shí)所屬于類,這時(shí)有可能還沒有該類產(chǎn)生的對象,但是該類的字節(jié)碼文件加載進(jìn)內(nèi)存就已經(jīng)被封裝成了對象,這個(gè)對象就是該類的字節(jié)碼文件對象。
所以靜態(tài)加載時(shí),只有一個(gè)對象存在,那么靜態(tài)同步函數(shù)就使用的這個(gè)對象。
這個(gè)對象就是 類名.class
同步代碼塊和同步函數(shù)的區(qū)別?
同步代碼塊使用的鎖可以是任意對象。
同步函數(shù)使用的鎖是this,靜態(tài)同步函數(shù)的鎖是該類的字節(jié)碼文件對象。
在一個(gè)類中只有一個(gè)同步,可以使用同步函數(shù)。如果有多同步,必須使用同步代碼塊,來確定不同的鎖。所以同步代碼塊相對靈活一些。
-------------------------------------------------------
★考點(diǎn)問題:請寫一個(gè)延遲加載的單例模式?寫懶漢式;當(dāng)出現(xiàn)多線程訪問時(shí)怎么解決?加同步,解決安全問題;效率高嗎?不高;怎樣解決?通過雙重判斷的形式解決。
//懶漢式:延遲加載方式。
當(dāng)多線程訪問懶漢式時(shí),因?yàn)閼袧h式的方法內(nèi)對共性數(shù)據(jù)進(jìn)行多條語句的操作。所以容易出現(xiàn)線程安全問題。為了解決,加入同步機(jī)制,解決安全問題。但是卻帶來了效率降低。
為了效率問題,通過雙重判斷的形式解決。
class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){ //鎖是誰?字節(jié)碼文件對象;
if(s == null){
synchronized(Single.class){
if(s == null)
s = new Single();
}
}
return s;
}
}
---------------------------------------------------------
同步死鎖:通常只要將同步進(jìn)行嵌套,就可以看到現(xiàn)象。同步函數(shù)中有同步代碼塊,同步代碼塊中還有同步函數(shù)。
線程間通信:思路:多個(gè)線程在操作同一個(gè)資源,但是操作的動(dòng)作卻不一樣。
1:將資源封裝成對象。
2:將線程執(zhí)行的任務(wù)(任務(wù)其實(shí)就是run方法。)也封裝成對象。
等待喚醒機(jī)制:涉及的方法:
wait:將同步中的線程處于凍結(jié)狀態(tài)。釋放了執(zhí)行權(quán),釋放了資格。同時(shí)將線程對象存儲到線程池中。
notify:喚醒線程池中某一個(gè)等待線程。
notifyAll:喚醒的是線程池中的所有線程。
注意:
1:這些方法都需要定義在同步中。
2:因?yàn)檫@些方法必須要標(biāo)示所屬的鎖。
你要知道 A鎖上的線程被wait了,那這個(gè)線程就相當(dāng)于處于A鎖的線程池中,只能A鎖的notify喚醒。
3:這三個(gè)方法都定義在Object類中。為什么操作線程的方法定義在Object類中?
因?yàn)檫@三個(gè)方法都需要定義同步內(nèi),并標(biāo)示所屬的同步鎖,既然被鎖調(diào)用,而鎖又可以是任意對象,那么能被任意對象調(diào)用的方法一定定義在Object類中。
wait和sleep區(qū)別: 分析這兩個(gè)方法:從執(zhí)行權(quán)和鎖上來分析:
wait:可以指定時(shí)間也可以不指定時(shí)間。不指定時(shí)間,只能由對應(yīng)的notify或者notifyAll來喚醒。
sleep:必須指定時(shí)間,時(shí)間到自動(dòng)從凍結(jié)狀態(tài)轉(zhuǎn)成運(yùn)行狀態(tài)(臨時(shí)阻塞狀態(tài))。
wait:線程會釋放執(zhí)行權(quán),而且線程會釋放鎖。
Sleep:線程會釋放執(zhí)行權(quán),但不是不釋放鎖。
線程的停止:通過stop方法就可以停止線程。但是這個(gè)方式過時(shí)了。
停止線程:原理就是:讓線程運(yùn)行的代碼結(jié)束,也就是結(jié)束run方法。
怎么結(jié)束run方法?一般run方法里肯定定義循環(huán)。所以只要結(jié)束循環(huán)即可。
第一種方式:定義循環(huán)的結(jié)束標(biāo)記。
第二種方式:如果線程處于了凍結(jié)狀態(tài),是不可能讀到標(biāo)記的,這時(shí)就需要通過Thread類中的interrupt方法,將其凍結(jié)狀態(tài)強(qiáng)制清除。讓線程恢復(fù)具備執(zhí)行資格的狀態(tài),讓線程可以讀到標(biāo)記,并結(jié)束。
---------< java.lang.Thread >----------
interrupt():中斷線程。
setPriority(int newPriority):更改線程的優(yōu)先級。
getPriority():返回線程的優(yōu)先級。
toString():返回該線程的字符串表示形式,包括線程名稱、優(yōu)先級和線程組。
Thread.yield():暫停當(dāng)前正在執(zhí)行的線程對象,并執(zhí)行其他線程。
setDaemon(true):將該線程標(biāo)記為守護(hù)線程或用戶線程。將該線程標(biāo)記為守護(hù)線程或用戶線程。當(dāng)正在運(yùn)行的線程都是守護(hù)線程時(shí),Java 虛擬機(jī)退出。該方法必須在啟動(dòng)線程前調(diào)用。
join:臨時(shí)加入一個(gè)線程的時(shí)候可以使用join方法。
當(dāng)A線程執(zhí)行到了B線程的join方式。A線程處于凍結(jié)狀態(tài),釋放了執(zhí)行權(quán),B開始執(zhí)行。A什么時(shí)候執(zhí)行呢?只有當(dāng)B線程運(yùn)行結(jié)束后,A才從凍結(jié)狀態(tài)恢復(fù)運(yùn)行狀態(tài)執(zhí)行。
-----------------------------------------------------------
Lock接口:多線程在JDK1.5版本升級時(shí),推出一個(gè)接口Lock接口。
解決線程安全問題使用同步的形式,(同步代碼塊,要么同步函數(shù))其實(shí)最終使用的都是鎖機(jī)制。
到了后期版本,直接將鎖封裝成了對象。線程進(jìn)入同步就是具備了鎖,執(zhí)行完,離開同步,就是釋放了鎖。
在后期對鎖的分析過程中,發(fā)現(xiàn),獲取鎖,或者釋放鎖的動(dòng)作應(yīng)該是鎖這個(gè)事物更清楚。所以將這些動(dòng)作定義在了鎖當(dāng)中,并把鎖定義成對象。
所以同步是隱示的鎖操作,而Lock對象是顯示的鎖操作,它的出現(xiàn)就替代了同步。
在之前的版本中使用Object類中wait、notify、notifyAll的方式來完成的。那是因?yàn)橥街械逆i是任意對象,所以操作鎖的等待喚醒的方法都定義在Object類中。
而現(xiàn)在鎖是指定對象Lock。所以查找等待喚醒機(jī)制方式需要通過Lock接口來完成。而Lock接口中并沒有直接操作等待喚醒的方法,而是將這些方式又單獨(dú)封裝到了一個(gè)對象中。這個(gè)對象就是Condition,將Object中的三個(gè)方法進(jìn)行單獨(dú)的封裝。并提供了功能一致的方法 await()、signal()、signalAll()體現(xiàn)新版本對象的好處。
< java.util.concurrent.locks > Condition接口:await()、signal()、signalAll();
--------------------------------------------------------
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
}
finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
}
finally {
lock.unlock();
}
}
}
------------------------------------------------------------------------------------------------
API:(Application Programming Interface,應(yīng)用程序編程接口)是一些預(yù)先定義的函數(shù),目的是提供應(yīng)用程序與開發(fā)人員基于某軟件或硬件的以訪問一組例程的能力,而又無需訪問源碼,或理解內(nèi)部工作機(jī)制的細(xì)節(jié)。
--< java.lang >-- String字符串:★★★☆
java中用String類進(jìn)行描述。對字符串進(jìn)行了對象的封裝。這樣的好處是可以對字符串這種常見數(shù)據(jù)進(jìn)行方便的操作。對象封裝后,可以定義N多屬性和行為。
如何定義字符串對象呢?String s = "abc";只要是雙引號引起的數(shù)據(jù)都是字符串對象。
特點(diǎn):字符串一旦被初始化,就不可以被改變,存放在方法區(qū)中的常量池中。
------------------------------------------------------
String s1 = "abc"; // s1指向的內(nèi)存中只有一個(gè)對象abc。
String s2 = new String("abc"); // s2指向的內(nèi)容中有兩個(gè)對象abc、new 。
System.out.println(s1==s2);//false ==比較的是地址值
System.out.println(s1.equals(s2));//true ,字符串中equals比較的是字符串內(nèi)容是否相同。
而在Object中,equals比較的是兩個(gè)對象的地址值,是否為相同。
查API。
-------------------------------------------------------
字符串的方法:
1:構(gòu)造方法:將字節(jié)數(shù)組或者字符數(shù)組轉(zhuǎn)成字符串。
String s1 = new String();//創(chuàng)建了一個(gè)空內(nèi)容的字符串。
String s2 = null;//s2沒有任何對象指向,是一個(gè)null常量值。
String s3 = "";//s3指向一個(gè)具體的字符串對象,只不過這個(gè)字符串中沒有內(nèi)容。
//一般在定義字符串時(shí),不用new。
String s4 = new String("abc");
String s5 = "abc"; 一般用此寫法
new String(char[]);//將字符數(shù)組轉(zhuǎn)成字符串。
new String(char[],offset,count);//將字符數(shù)組中的一部分轉(zhuǎn)成字符串。
2:一般方法:
按照面向?qū)ο蟮乃枷耄?/p>
2.1 獲?。?/strong>
2.1.1:獲取字符串的長度。length();
2.1.2:指定位置的字符。char charAt(int index);
2.1.3:獲取指定字符的位置。如果不存在返回-1,所以可以通過返回值-1來判斷某一個(gè)字符不存在的情況。
int indexOf(int ch);//返回第一次找到的字符角標(biāo)
int indexOf(int ch,int fromIndex); //返回從指定位置開始第一次找到的角標(biāo)
int indexOf(String str); //返回第一次找到的字符串角標(biāo)
int indexOf(String str,int fromIndex);
int lastIndexOf(int ch);
int lastIndexOf(int ch,int fromIndex);
int lastIndexOf(String str);
int lastIndexOf(String str,int fromIndex);
2.1.4:獲取子串。
String substring(int start);//從start位開始,到length()-1為止.
String substring(int start,int end);//從start開始到end為止。//包含start位,不包含end位。
substring(0,str.length());//獲取整串
2.2 判斷:
2.2.1:字符串中包含指定的字符串嗎?
boolean contains(String substring);
2.2.2:字符串是否以指定字符串開頭?。?/p>
boolean startsWith(string);
2.2.3:字符串是否以指定字符串結(jié)尾???
boolean endsWith(string);
2.2.4:判斷字符串是否相同
boolean equals(string);//覆蓋了Object中的方法,判斷字符串內(nèi)容是否相同。
2.2.5:判斷字符串內(nèi)容是否相同,忽略大小寫。
boolean equalsIgnoreCase(string) ;
2.3 轉(zhuǎn)換:
2.3.1:通過構(gòu)造函數(shù)可以將字符數(shù)組或者字節(jié)數(shù)組轉(zhuǎn)成字符串。
2.3.2:可以通過字符串中的靜態(tài)方法,將字符數(shù)組轉(zhuǎn)成字符串。
static String copyValueOf(char[] );
static String copyValueOf(char[],int offset,int count);
static String valueOf(char[]);
static String valueOf(char[],int offset,int count);
2.3.3:將基本數(shù)據(jù)類型或者對象轉(zhuǎn)成字符串。
static String valueOf(char);
static String valueOf(boolean);
static String valueOf(double);
static String valueOf(float);
static String valueOf(int);
static String valueOf(long);
static String valueOf(Object);
2.3.4:將字符串轉(zhuǎn)成大小寫。
String toLowerCase();
String toUpperCase();
2.3.5:將字符串轉(zhuǎn)成數(shù)組。
char[] toCharArray();//轉(zhuǎn)成字符數(shù)組。
byte[] getBytes();//可以加入編碼表。轉(zhuǎn)成字節(jié)數(shù)組。
2.3.6:將字符串轉(zhuǎn)成字符串?dāng)?shù)組。切割方法。
String[] split(分割的規(guī)則-字符串);
2.3.7:將字符串進(jìn)行內(nèi)容替換。注意:修改后變成新字符串,并不是將原字符串直接修改。
String replace(oldChar,newChar);
String replace(oldstring,newstring);
2.3.8: String concat(string); //對字符串進(jìn)行追加。
String trim();//去除字符串兩端的空格
int compareTo();//如果參數(shù)字符串等于此字符串,則返回值 0;如果此字符串按字典順序小于字符串參數(shù),則返回一個(gè)小于 0 的值;如果此字符串按字典順序大于字符串參數(shù),則返回一個(gè)大于 0 的值。
------------------------------------------------------------------------------------------------
--< java.lang >-- StringBuffer字符串緩沖區(qū):★★★☆
構(gòu)造一個(gè)其中不帶字符的字符串緩沖區(qū),初始容量為 16 個(gè)字符。
特點(diǎn):
1:可以對字符串內(nèi)容進(jìn)行修改。
2:是一個(gè)容器。
3:是可變長度的。
4:緩沖區(qū)中可以存儲任意類型的數(shù)據(jù)。
5:最終需要變成字符串。
容器通常具備一些固定的方法:
1,添加。
StringBuffer append(data):在緩沖區(qū)中追加數(shù)據(jù)。追加到尾部。
StringBuffer insert(index,data):在指定位置插入數(shù)據(jù)。
2,刪除。
StringBuffer delete(start,end);刪除從start至end-1范圍的元素
StringBuffer deleteCharAt(index);刪除指定位置的元素
//sb.delete(0,sb.length());//清空緩沖區(qū)。
3,修改。
StringBuffer replace(start,end,string);將start至end-1替換成string
void setCharAt(index,char);替換指定位置的字符
void setLength(len);將原字符串置為指定長度的字符串
4,查找。(查不到返回-1)
int indexOf(string); 返回指定子字符串在此字符串中第一次出現(xiàn)處的索引。
int indexOf(string,int fromIndex);從指定位置開始查找字符串
int lastIndexOf(string); 返回指定子字符串在此字符串中最右邊出現(xiàn)處的索引。
int lastIndexOf(string,int fromIndex); 從指定的索引開始反向搜索
5,獲取子串。
string substring(start); 返回start到結(jié)尾的子串
string substring(start,end); 返回start至end-1的子串
6,反轉(zhuǎn)。
StringBuffer reverse();字符串反轉(zhuǎn)
------------------------------------------------------------------------------------------------
--< java.lang >-- StringBuilder字符串緩沖區(qū):★★★☆
JDK1.5出現(xiàn)StringBuiler;構(gòu)造一個(gè)其中不帶字符的字符串生成器,初始容量為 16 個(gè)字符。該類被設(shè)計(jì)用作 StringBuffer 的一個(gè)簡易替換,用在字符串緩沖區(qū)被單個(gè)線程使用的時(shí)候(這種情況很普遍)。
方法和StringBuffer一樣;
StringBuffer 和 StringBuilder 的區(qū)別:
StringBuffer線程安全。
StringBuilder線程不安全。
單線程操作,使用StringBuilder 效率高。
多線程操作,使用StringBuffer 安全。
---------------------------------------------------------
StringBuilder sb = new StringBuilder("abcdefg");
sb.append("ak"); //abcdefgak
sb.insert(1,"et");//aetbcdefg
sb.deleteCharAt(2);//abdefg
sb.delete(2,4);//abefg
sb.setLength(4);//abcd
sb.setCharAt(0,'k');//kbcdefg
sb.replace(0,2,"hhhh");//hhhhcdefg
//想要使用緩沖區(qū),先要建立對象。
StringBuffer sb = new StringBuffer();
sb.append(12).append("haha");//方法調(diào)用鏈。
String s = "abc"+4+'q';
s = new StringBuffer().append("abc").append(4).append('q').toString();
---------------------------------------------------------
class Test{
public static void main(String[] args) {
String s1 = "java";
String s2 = "hello";
method_1(s1,s2);
System.out.println(s1+"...."+s2); //java....hello
StringBuilder s11 = new StringBuilder("java");
StringBuilder s22 = new StringBuilder("hello");
method_2(s11,s22);
System.out.println(s11+"-----"+s22); //javahello-----hello
}
public static void method_1(String s1,String s2){
s1.replace('a','k');
s1 = s2;
}
public static void method_2(StringBuilder s1,StringBuilder s2){
s1.append(s2);
s1 = s2;
}
}
---------------------------------------------------------
基本數(shù)據(jù)類型對象包裝類:是按照面向?qū)ο笏枷雽⒒緮?shù)據(jù)類型封裝成了對象。
好處:
1:可以通過對象中的屬性和行為操作基本數(shù)據(jù)。
2:可以實(shí)現(xiàn)基本數(shù)據(jù)類型和字符串之間的轉(zhuǎn)換。
關(guān)鍵字 對應(yīng)的類名
byte Byte
short Short paserShort(numstring);
int Integer 靜態(tài)方法:parseInt(numstring)
long Long
float Float
double Double
char Character
Boolean Boolean
基本數(shù)據(jù)類型對象包裝類:都有 XXX parseXXX 方法
只有一個(gè)類型沒有parse方法:Character ;
--------------------------------------------------------
Integer對象: ★★★☆
數(shù)字格式的字符串轉(zhuǎn)成基本數(shù)據(jù)類型的方法:
1:將該字符串封裝成了Integer對象,并調(diào)用對象的方法intValue();
2:使用Integer.parseInt(numstring):不用建立對象,直接類名調(diào)用;
將基本類型轉(zhuǎn)成字符串:
1:Integer中的靜態(tài)方法 String toString(int);
2:int+"";
將一個(gè)十進(jìn)制整數(shù)轉(zhuǎn)成其他進(jìn)制:
轉(zhuǎn)成二進(jìn)制:toBinaryString
轉(zhuǎn)成八進(jìn)制:toOctalString
轉(zhuǎn)成十六進(jìn)制:toHexString
toString(int num,int radix);
將其他進(jìn)制轉(zhuǎn)換十進(jìn)制:
parseInt(string,radix); //將給定的數(shù)轉(zhuǎn)成指定的基數(shù)進(jìn)制;
在jdk1.5版本后,對基本數(shù)據(jù)類型對象包裝類進(jìn)行升級。在升級中,使用基本數(shù)據(jù)類型對象包裝類可以像使用基本數(shù)據(jù)類型一樣,進(jìn)行運(yùn)算。
Integer i = new Integer(4); //1.5版本之前的寫法;
Integer i = 4; //自動(dòng)裝箱,1.5版本后的寫法;
i = i + 5;
//i對象是不能直接和5相加的,其實(shí)底層先將i轉(zhuǎn)成int類型,在和5相加。而轉(zhuǎn)成int類型的操作是隱式的。自動(dòng)拆箱:拆箱的原理就是i.intValue();i+5運(yùn)算完是一個(gè)int整數(shù)。如何賦值給引用類型i呢?其實(shí)有對結(jié)果進(jìn)行裝箱。
Integer c = 127;
Integer d = 127;
System.out.println(c = = d); //true
//在裝箱時(shí),如果數(shù)值在byte范圍之內(nèi),那么數(shù)值相同,不會產(chǎn)生新的對象,也就是說多個(gè)數(shù)值相同的引用指向的是同一個(gè)對象。
------------------------------------------------------------------------------------------------
集合框架:★★★★★,用于存儲數(shù)據(jù)的容器。
特點(diǎn):
1:對象封裝數(shù)據(jù),對象多了也需要存儲。集合用于存儲對象。
2:對象的個(gè)數(shù)確定可以使用數(shù)組,但是不確定怎么辦?可以用集合。因?yàn)?strong>集合是可變長度的。
集合和數(shù)組的區(qū)別:
1:數(shù)組是固定長度的;集合可變長度的。
2:數(shù)組可以存儲基本數(shù)據(jù)類型,也可以存儲引用數(shù)據(jù)類型;集合只能存儲引用數(shù)據(jù)類型。
3:數(shù)組存儲的元素必須是同一個(gè)數(shù)據(jù)類型;集合存儲的對象可以是不同數(shù)據(jù)類型。
數(shù)據(jù)結(jié)構(gòu):就是容器中存儲數(shù)據(jù)的方式。
對于集合容器,有很多種。因?yàn)槊恳粋€(gè)容器的自身特點(diǎn)不同,其實(shí)原理在于每個(gè)容器的內(nèi)部數(shù)據(jù)結(jié)構(gòu)不同。
集合容器在不斷向上抽取過程中。出現(xiàn)了集合體系。
在使用一個(gè)體系時(shí),原則:參閱頂層內(nèi)容。建立底層對象。
------------------------------------------------------------
--< java.util >-- Collection接口:
Collection:
|--List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重復(fù)。
|--Set:無序(存入和取出順序有可能不一致),不可以存儲重復(fù)元素。必須保證元素唯一性。
1,添加:
add(object):添加一個(gè)元素
addAll(Collection) :添加一個(gè)集合中的所有元素。
2,刪除:
clear():將集合中的元素全刪除,清空集合。
remove(obj) :刪除集合中指定的對象。注意:刪除成功,集合的長度會改變。
removeAll(collection) :刪除部分元素。部分元素和傳入Collection一致。
3,判斷:
boolean contains(obj) :集合中是否包含指定元素 。
boolean containsAll(Collection) :集合中是否包含指定的多個(gè)元素。
boolean isEmpty():集合中是否有元素。
4,獲?。?/strong>
int size():集合中有幾個(gè)元素。
5,取交集:
boolean retainAll(Collection) :對當(dāng)前集合中保留和指定集合中的相同的元素。如果兩個(gè)集合元素相同,返回flase;如果retainAll修改了當(dāng)前集合,返回true。
6,獲取集合中所有元素:
Iterator iterator():迭代器
7,將集合變成數(shù)組:
toArray();
------------------------------------------------------------
--< java.util >-- Iterator接口:
迭代器:是一個(gè)接口。作用:用于取集合中的元素。
boolean | hasNext() 如果仍有元素可以迭代,則返回 true。 |
E | next() 返回迭代的下一個(gè)元素。 |
void | remove() 從迭代器指向的 collection 中移除迭代器返回的最后一個(gè)元素(可選操作)。 |
每一個(gè)集合都有自己的數(shù)據(jù)結(jié)構(gòu),都有特定的取出自己內(nèi)部元素的方式。為了便于操作所有的容器,取出元素。將容器內(nèi)部的取出方式按照一個(gè)統(tǒng)一的規(guī)則向外提供,這個(gè)規(guī)則就是Iterator接口。
也就說,只要通過該接口就可以取出Collection集合中的元素,至于每一個(gè)具體的容器依據(jù)自己的數(shù)據(jù)結(jié)構(gòu),如何實(shí)現(xiàn)的具體取出細(xì)節(jié),這個(gè)不用關(guān)心,這樣就降低了取出元素和具體集合的耦合性。
Iterator it = coll.iterator();//獲取容器中的迭代器對象,至于這個(gè)對象是是什么不重要。這對象肯定符合一個(gè)規(guī)則Iterator接口。
-----------------------------------------------------------------------------
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc0");
coll.add("abc1");
coll.add("abc2");
//--------------方式1----------------------
Iterator it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//---------------方式2用此種----------------------
for(Iterator it = coll.iterator();it.hasNext(); ){
System.out.println(it.next());
}
}
-----------------------------------------------------------------------------
--< java.util >-- List接口:
List本身是Collection接口的子接口,具備了Collection的所有方法。現(xiàn)在學(xué)習(xí)List體系特有的共性方法,查閱方法發(fā)現(xiàn)List的特有方法都有索引,這是該集合最大的特點(diǎn)。
List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重復(fù)。
|--ArrayList:底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,線程不同步,ArrayList替代了Vector,查詢元素的速度非???。
|--LinkedList:底層的數(shù)據(jù)結(jié)構(gòu)是鏈表,線程不同步,增刪元素的速度非??臁?/strong>
|--Vector:底層的數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,線程同步的,Vector無論查詢和增刪都巨慢。
1,添加:
add(index,element) :在指定的索引位插入元素。
addAll(index,collection) :在指定的索引位插入一堆元素。
2,刪除:
remove(index) :刪除指定索引位的元素。 返回被刪的元素。
3,獲?。?/strong>
Object get(index) :通過索引獲取指定元素。
int indexOf(obj) :獲取指定元素第一次出現(xiàn)的索引位,如果該元素不存在返回-1;
所以,通過-1,可以判斷一個(gè)元素是否存在。
int lastIndexOf(Object o) :反向索引指定元素的位置。
List subList(start,end) :獲取子列表。
4,修改:
Object set(index,element) :對指定索引位進(jìn)行元素的修改。
5,獲取所有元素:
ListIterator listIterator():list集合特有的迭代器。
List集合支持對元素的增、刪、改、查。
List集合因?yàn)榻菢?biāo)有了自己的獲取元素的方式: 遍歷。
for(int x=0; x<list.size(); x++){
sop("get:"+list.get(x));
}
在進(jìn)行l(wèi)ist列表元素迭代的時(shí)候,如果想要在迭代過程中,想要對元素進(jìn)行操作的時(shí)候,比如滿足條件添加新元素。會發(fā)生.ConcurrentModificationException并發(fā)修改異常。
導(dǎo)致的原因是:
集合引用和迭代器引用在同時(shí)操作元素,通過集合獲取到對應(yīng)的迭代器后,在迭代中,進(jìn)行集合引用的元素添加,迭代器并不知道,所以會出現(xiàn)異常情況。
如何解決呢?
既然是在迭代中對元素進(jìn)行操作,找迭代器的方法最為合適.可是Iterator中只有hasNext,next,remove方法.通過查閱的它的子接口,ListIterator,發(fā)現(xiàn)該列表迭代器接口具備了對元素的增、刪、改、查的動(dòng)作。
ListIterator是List集合特有的迭代器。
ListIterator it = list.listIterator;//取代Iterator it = list.iterator;
方法摘要 | |
void | add(E e) 將指定的元素插入列表(可選操作)。 |
boolean | hasNext() 以正向遍歷列表時(shí),如果列表迭代器有多個(gè)元素,則返回 true(換句話說,如果 next 返回一個(gè)元素而不是拋出異常,則返回 true)。 |
boolean | hasPrevious() 如果以逆向遍歷列表,列表迭代器有多個(gè)元素,則返回 true。 |
E | next() 返回列表中的下一個(gè)元素。 |
int | nextIndex() 返回對 next 的后續(xù)調(diào)用所返回元素的索引。 |
E | previous() 返回列表中的前一個(gè)元素。 |
int | previousIndex() 返回對 previous 的后續(xù)調(diào)用所返回元素的索引。 |
void | remove() 從列表中移除由 next 或 previous 返回的最后一個(gè)元素(可選操作)。 |
void | set(E e) 用指定元素替換 next 或 previous 返回的最后一個(gè)元素(可選操作)。 |
可變長度數(shù)組的原理:
當(dāng)元素超出數(shù)組長度,會產(chǎn)生一個(gè)新數(shù)組,將原數(shù)組的數(shù)據(jù)復(fù)制到新數(shù)組中,再將新的元素添加到新數(shù)組中。
ArrayList:是按照原數(shù)組的50%延長。構(gòu)造一個(gè)初始容量為 10 的空列表。
Vector:是按照原數(shù)組的100%延長。
注意:對于list集合,底層判斷元素是否相同,其實(shí)用的是元素自身的equals方法完成的。所以建議元素都要復(fù)寫equals方法,建立元素對象自己的比較相同的條件依據(jù)。
LinkedList:的特有方法。
addFirst();
addLast();
在jdk1.6以后。
offerFirst();
offerLast();
getFirst():獲取鏈表中的第一個(gè)元素。如果鏈表為空,拋出NoSuchElementException;
getLast();
在jdk1.6以后。
peekFirst();獲取鏈表中的第一個(gè)元素。如果鏈表為空,返回null。
peekLast();
removeFirst():獲取鏈表中的第一個(gè)元素,但是會刪除鏈表中的第一個(gè)元素。如果鏈表為空,拋出NoSuchElementException
removeLast();
在jdk1.6以后。
pollFirst();獲取鏈表中的第一個(gè)元素,但是會刪除鏈表中的第一個(gè)元素。如果鏈表為空,返回null。
pollLast();
------------------------------------------------------------
--< java.util >-- Set接口:
Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一種,迭代器。
|--HashSet:底層數(shù)據(jù)結(jié)構(gòu)是哈希表,線程是不同步的。無序,高效;
HashSet集合保證元素唯一性:通過元素的hashCode方法,和equals方法完成的。
當(dāng)元素的hashCode值相同時(shí),才繼續(xù)判斷元素的equals是否為true。
如果為true,那么視為相同元素,不存。如果為false,那么存儲。
如果hashCode值不同,那么不判斷equals,從而提高對象比較的速度。
|--LinkedHashSet:有序,hashset的子類。
|--TreeSet:對Set集合中的元素的進(jìn)行指定順序的排序。不同步。TreeSet底層的數(shù)據(jù)結(jié)構(gòu)就是二叉樹。
哈希表的原理:
1,對對象元素中的關(guān)鍵字(對象中的特有數(shù)據(jù)),進(jìn)行哈希算法的運(yùn)算,并得出一個(gè)具體的算法值,這個(gè)值 稱為哈希值。
2,哈希值就是這個(gè)元素的位置。
3,如果哈希值出現(xiàn)沖突,再次判斷這個(gè)關(guān)鍵字對應(yīng)的對象是否相同。如果對象相同,就不存儲,因?yàn)樵刂貜?fù)。如果對象不同,就存儲,在原來對象的哈希值基礎(chǔ) +1順延。
4,存儲哈希值的結(jié)構(gòu),我們稱為哈希表。
5,既然哈希表是根據(jù)哈希值存儲的,為了提高效率,最好保證對象的關(guān)鍵字是唯一的。
這樣可以盡量少的判斷關(guān)鍵字對應(yīng)的對象是否相同,提高了哈希表的操作效率。
對于ArrayList集合,判斷元素是否存在,或者刪元素底層依據(jù)都是equals方法。
對于HashSet集合,判斷元素是否存在,或者刪除元素,底層依據(jù)的是hashCode方法和equals方法。
TreeSet:
用于對Set集合進(jìn)行元素的指定順序排序,排序需要依據(jù)元素自身具備的比較性。
如果元素不具備比較性,在運(yùn)行時(shí)會發(fā)生ClassCastException異常。
所以需要元素實(shí)現(xiàn)Comparable接口,強(qiáng)制讓元素具備比較性,復(fù)寫compareTo方法。
依據(jù)compareTo方法的返回值,確定元素在TreeSet數(shù)據(jù)結(jié)構(gòu)中的位置。
TreeSet方法保證元素唯一性的方式:就是參考比較方法的結(jié)果是否為0,如果return 0,視為兩個(gè)對象重復(fù),不存。
注意:在進(jìn)行比較時(shí),如果判斷元素不唯一,比如,同姓名,同年齡,才視為同一個(gè)人。
在判斷時(shí),需要分主要條件和次要條件,當(dāng)主要條件相同時(shí),再判斷次要條件,按照次要條件排序。
TreeSet集合排序有兩種方式,Comparable和Comparator區(qū)別:
1:讓元素自身具備比較性,需要元素對象實(shí)現(xiàn)Comparable接口,覆蓋compareTo方法。
2:讓集合自身具備比較性,需要定義一個(gè)實(shí)現(xiàn)了Comparator接口的比較器,并覆蓋compare方法,并將該類對象作為實(shí)際參數(shù)傳遞給TreeSet集合的構(gòu)造函數(shù)。
第二種方式較為靈活。
------------------------------------------------------------
Map集合:
|--Hashtable:底層是哈希表數(shù)據(jù)結(jié)構(gòu),是線程同步的。不可以存儲null鍵,null值。
|--HashMap:底層是哈希表數(shù)據(jù)結(jié)構(gòu),是線程不同步的??梢源鎯ull鍵,null值。替代了Hashtable.
|--TreeMap:底層是二叉樹結(jié)構(gòu),可以對map集合中的鍵進(jìn)行指定順序的排序。
Map集合存儲和Collection有著很大不同:
Collection一次存一個(gè)元素;Map一次存一對元素。
Collection是單列集合;Map是雙列集合。
Map中的存儲的一對元素:一個(gè)是鍵,一個(gè)是值,鍵與值之間有對應(yīng)(映射)關(guān)系。
特點(diǎn):要保證map集合中鍵的唯一性。
1,添加。
put(key,value):當(dāng)存儲的鍵相同時(shí),新的值會替換老的值,并將老值返回。如果鍵沒有重復(fù),返回null。
void putAll(Map);
2,刪除。
void clear():清空
value remove(key) :刪除指定鍵。
3,判斷。
boolean isEmpty():
boolean containsKey(key):是否包含key
boolean containsValue(value) :是否包含value
4,取出。
int size():返回長度
value get(key) :通過指定鍵獲取對應(yīng)的值。如果返回null,可以判斷該鍵不存在。當(dāng)然有特殊情況,就是在hashmap集合中,是可以存儲null鍵null值的。
Collection values():獲取map集合中的所有的值。
5,想要獲取map中的所有元素:
原理:map中是沒有迭代器的,collection具備迭代器,只要將map集合轉(zhuǎn)成Set集合,可以使用迭代器了。之所以轉(zhuǎn)成set,是因?yàn)閙ap集合具備著鍵的唯一性,其實(shí)set集合就來自于map,set集合底層其實(shí)用的就是map的方法。
★ 把map集合轉(zhuǎn)成set的方法:
Set keySet();
Set entrySet();//取的是鍵和值的映射關(guān)系。
Entry就是Map接口中的內(nèi)部接口;
為什么要定義在map內(nèi)部呢?entry是訪問鍵值關(guān)系的入口,是map的入口,訪問的是map中的鍵值對。
---------------------------------------------------------
取出map集合中所有元素的方式一:keySet()方法。
可以將map集合中的鍵都取出存放到set集合中。對set集合進(jìn)行迭代。迭代完成,再通過get方法對獲取到的鍵進(jìn)行值的獲取。
Set keySet = map.keySet();
Iterator it = keySet.iterator();
while(it.hasNext()) {
Object key = it.next();
Object value = map.get(key);
System.out.println(key+":"+value);
}
--------------------------------------------------------
取出map集合中所有元素的方式二:entrySet()方法。
Set entrySet = map.entrySet();
Iterator it = entrySet.iterator();
while(it.hasNext()) {
Map.Entry me = (Map.Entry)it.next();
System.out.println(me.getKey()+"::::"+me.getValue());
}
--------------------------------------------------------
使用集合的技巧:
看到Array就是數(shù)組結(jié)構(gòu),有角標(biāo),查詢速度很快。
看到link就是鏈表結(jié)構(gòu):增刪速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();
看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到該結(jié)構(gòu)的中的元素必須覆蓋hashCode,equals方法。
看到tree就是二叉樹,就要想到排序,就想要用到比較。
比較的兩種方式:
一個(gè)是Comparable:覆蓋compareTo方法;
一個(gè)是Comparator:覆蓋compare方法。
LinkedHashSet,LinkedHashMap:這兩個(gè)集合可以保證哈希表有存入順序和取出順序一致,保證哈希表有序。
集合什么時(shí)候用?
當(dāng)存儲的是一個(gè)元素時(shí),就用Collection。當(dāng)存儲對象之間存在著映射關(guān)系時(shí),就使用Map集合。
保證唯一,就用Set。不保證唯一,就用List。
------------------------------------------------------------------------------------------------
Collections:它的出現(xiàn)給集合操作提供了更多的功能。這個(gè)類不需要?jiǎng)?chuàng)建對象,內(nèi)部提供的都是靜態(tài)方法。
靜態(tài)方法:
Collections.sort(list);//list集合進(jìn)行元素的自然順序排序。
Collections.sort(list,new ComparatorByLen());//按指定的比較器方法排序。
class ComparatorByLen implements Comparator<String>{
public int compare(String s1,String s2){
int temp = s1.length()-s2.length();
return temp==0?s1.compareTo(s2):temp;
}
}
Collections.max(list); //返回list中字典順序最大的元素。
int index = Collections.binarySearch(list,"zz");//二分查找,返回角標(biāo)。
Collections.reverseOrder();//逆向反轉(zhuǎn)排序。
Collections.shuffle(list);//隨機(jī)對list中的元素進(jìn)行位置的置換。
將非同步集合轉(zhuǎn)成同步集合的方法:Collections中的 XXX synchronizedXXX(XXX);
List synchronizedList(list);
Map synchronizedMap(map);
原理:定義一個(gè)類,將集合所有的方法加同一把鎖后返回。
Collection 和 Collections的區(qū)別:
Collections是個(gè)java.util下的類,是針對集合類的一個(gè)工具類,提供一系列靜態(tài)方法,實(shí)現(xiàn)對集合的查找、排序、替換、線程安全化(將非同步的集合轉(zhuǎn)換成同步的)等操作。
Collection是個(gè)java.util下的接口,它是各種集合結(jié)構(gòu)的父接口,繼承于它的接口主要有Set和List,提供了關(guān)于集合的一些操作,如插入、刪除、判斷一個(gè)元素是否其成員、遍歷等。
-------------------------------------------------------
Arrays:
用于操作數(shù)組對象的工具類,里面都是靜態(tài)方法。
asList方法:將數(shù)組轉(zhuǎn)換成list集合。
String[] arr = {"abc","kk","qq"};
List<String> list = Arrays.asList(arr);//將arr數(shù)組轉(zhuǎn)成list集合。
將數(shù)組轉(zhuǎn)換成集合,有什么好處呢?用aslist方法,將數(shù)組變成集合;
可以通過list集合中的方法來操作數(shù)組中的元素:isEmpty()、contains、indexOf、set;
注意(局限性):數(shù)組是固定長度,不可以使用集合對象增加或者刪除等,會改變數(shù)組長度的功能方法。比如add、remove、clear。(會報(bào)不支持操作異常UnsupportedOperationException);
如果數(shù)組中存儲的引用數(shù)據(jù)類型,直接作為集合的元素可以直接用集合方法操作。
如果數(shù)組中存儲的是基本數(shù)據(jù)類型,asList會將數(shù)組實(shí)體作為集合元素存在。
集合變數(shù)組:用的是Collection接口中的方法:toArray();
如果給toArray傳遞的指定類型的數(shù)據(jù)長度小于了集合的size,那么toArray方法,會自定再創(chuàng)建一個(gè)該類型的數(shù)據(jù),長度為集合的size。
如果傳遞的指定的類型的數(shù)組的長度大于了集合的size,那么toArray方法,就不會創(chuàng)建新數(shù)組,直接使用該數(shù)組即可,并將集合中的元素存儲到數(shù)組中,其他為存儲元素的位置默認(rèn)值null。
所以,在傳遞指定類型數(shù)組時(shí),最好的方式就是指定的長度和size相等的數(shù)組。
將集合變成數(shù)組后有什么好處?限定了對集合中的元素進(jìn)行增刪操作,只要獲取這些元素即可。
------------------------------------------------------------------------------------------------
Jdk5.0新特性:
Collection在jdk1.5以后,有了一個(gè)父接口Iterable,這個(gè)接口的出現(xiàn)的將iterator方法進(jìn)行抽取,提高了擴(kuò)展性。
--------------------------------------------------
增強(qiáng)for循環(huán):foreach語句,foreach簡化了迭代器。
格式:// 增強(qiáng)for循環(huán)括號里寫兩個(gè)參數(shù),第一個(gè)是聲明一個(gè)變量,第二個(gè)就是需要迭代的容器
for( 元素類型 變量名 : Collection集合 & 數(shù)組 ) {
…
}
高級for循環(huán)和傳統(tǒng)for循環(huán)的區(qū)別:
高級for循環(huán)在使用時(shí),必須要明確被遍歷的目標(biāo)。這個(gè)目標(biāo),可以是Collection集合或者數(shù)組,如果遍歷Collection集合,在遍歷過程中還需要對元素進(jìn)行操作,比如刪除,需要使用迭代器。
如果遍歷數(shù)組,還需要對數(shù)組元素進(jìn)行操作,建議用傳統(tǒng)for循環(huán)因?yàn)榭梢远x角標(biāo)通過角標(biāo)操作元素。如果只為遍歷獲取,可以簡化成高級for循環(huán),它的出現(xiàn)為了簡化書寫。
高級for循環(huán)可以遍歷map集合嗎?不可以。但是可以將map轉(zhuǎn)成set后再使用foreach語句。
1)、作用:對存儲對象的容器進(jìn)行迭代: 數(shù)組 collection map
2)、增強(qiáng)for循環(huán)迭代數(shù)組:
String [] arr = {"a", "b", "c"};//數(shù)組的靜態(tài)定義方式,只試用于數(shù)組首次定義的時(shí)候
for(String s : arr) {
System.out.println(s);
}
3)、單列集合 Collection:
List list = new ArrayList();
list.add("aaa");
// 增強(qiáng)for循環(huán), 沒有使用泛型的集合能不能使用增強(qiáng)for循環(huán)迭代?能
for(Object obj : list) {
String s = (String) obj;
System.out.println(s);
}
4)、雙列集合 Map:
Map map = new HashMap();
map.put("a", "aaa");
// 傳統(tǒng)方式:必須掌握這種方式
Set entrys = map.entrySet(); // 1.獲得所有的鍵值對Entry對象
iter = entrys.iterator(); // 2.迭代出所有的entry
while(iter.hasNext()) {
Map.Entry entry = (Entry) iter.next();
String key = (String) entry.getKey(); // 分別獲得key和value
String value = (String) entry.getValue();
System.out.println(key + "=" + value);
}
// 增強(qiáng)for循環(huán)迭代:原則上map集合是無法使用增強(qiáng)for循環(huán)來迭代的,因?yàn)樵鰪?qiáng)for循環(huán)只能針對實(shí)現(xiàn)了Iterable接口的集合進(jìn)行迭代;Iterable是jdk5中新定義的接口,就一個(gè)方法iterator方法,只有實(shí)現(xiàn)了Iterable接口的類,才能保證一定有iterator方法,java有這樣的限定是因?yàn)樵鰪?qiáng)for循環(huán)內(nèi)部還是用迭代器實(shí)現(xiàn)的,而實(shí)際上,我們可以通過某種方式來使用增強(qiáng)for循環(huán)。
for(Object obj : map.entrySet()) {
Map.Entry entry = (Entry) obj; // obj 依次表示Entry
System.out.println(entry.getKey() + "=" + entry.getValue());
}
5)、集合迭代注意問題:在迭代集合的過程中,不能對集合進(jìn)行增刪操作(會報(bào)并發(fā)訪問異常);可以用迭代器的方法進(jìn)行操作(子類listIterator:有增刪的方法)。
6)、增強(qiáng)for循環(huán)注意問題:在使用增強(qiáng)for循環(huán)時(shí),不能對元素進(jìn)行賦值;
int[] arr = {1,2,3};
for(int num : arr) {
num = 0; //不能改變數(shù)組的值
}
System.out.println(arr[1]); //2
--------------------------------------------------
可變參數(shù)(...):用到函數(shù)的參數(shù)上,當(dāng)要操作的同一個(gè)類型元素個(gè)數(shù)不確定的時(shí)候,可是用這個(gè)方式,這個(gè)參數(shù)可以接受任意個(gè)數(shù)的同一類型的數(shù)據(jù)。
和以前接收數(shù)組不一樣的是:
以前定義數(shù)組類型,需要先創(chuàng)建一個(gè)數(shù)組對象,再將這個(gè)數(shù)組對象作為參數(shù)傳遞給函數(shù)?,F(xiàn)在,直接將數(shù)組中的元素作為參數(shù)傳遞即可。底層其實(shí)是將這些元素進(jìn)行數(shù)組的封裝,而這個(gè)封裝動(dòng)作,是在底層完成的,被隱藏了。所以簡化了用戶的書寫,少了調(diào)用者定義數(shù)組的動(dòng)作。
如果在參數(shù)列表中使用了可變參數(shù),可變參數(shù)必須定義在參數(shù)列表結(jié)尾(也就是必須是最后一個(gè)參數(shù),否則編譯會失敗。)。
如果要獲取多個(gè)int數(shù)的和呢?可以使用將多個(gè)int數(shù)封裝到數(shù)組中,直接對數(shù)組求和即可。
---------------------------------------------------
靜態(tài)導(dǎo)入:導(dǎo)入了類中的所有靜態(tài)成員,簡化靜態(tài)成員的書寫。
import static java.util.Collections.*; //導(dǎo)入了Collections類中的所有靜態(tài)成員
---------------------------------------------------
枚舉:關(guān)鍵字 enum
問題:對象的某個(gè)屬性的值不能是任意的,必須為固定的一組取值其中的某一個(gè);
解決辦法:
1)、在setGrade方法中做判斷,不符合格式要求就拋出異常;
2)、直接限定用戶的選擇,通過自定義類模擬枚舉的方式來限定用戶的輸入,寫一個(gè)Grade類,私有構(gòu)造函數(shù),對外提供5個(gè)靜態(tài)的常量表示類的實(shí)例;
3)、jdk5中新定義了枚舉類型,專門用于解決此類問題;
4)、枚舉就是一個(gè)特殊的java類,可以定義屬性、方法、構(gòu)造函數(shù)、實(shí)現(xiàn)接口、繼承類;
------------------------------------------------------------------------------
自動(dòng)拆裝箱:java中數(shù)據(jù)類型分為兩種 : 基本數(shù)據(jù)類型 引用數(shù)據(jù)類型(對象)
在 java程序中所有的數(shù)據(jù)都需要當(dāng)做對象來處理,針對8種基本數(shù)據(jù)類型提供了包裝類,如下:
int --> Integer
byte --> Byte
short --> Short
long --> Long
char --> Character
double --> Double
float --> Float
boolean --> Boolean
jdk5以前基本數(shù)據(jù)類型和包裝類之間需要互轉(zhuǎn):
基本---引用 Integer x = new Integer(x);
引用---基本 int num = x.intValue();
1)、Integer x = 1; x = x + 1; 經(jīng)歷了什么過程?裝箱 à 拆箱 à 裝箱;
2)、為了優(yōu)化,虛擬機(jī)為包裝類提供了緩沖池,Integer池的大小 -128~127 一個(gè)字節(jié)的大小;
3)、String池:Java為了優(yōu)化字符串操作 提供了一個(gè)緩沖池;
----------------------------------------------------------
泛型:jdk1.5版本以后出現(xiàn)的一個(gè)安全機(jī)制。表現(xiàn)格式:< >
好處:
1:將運(yùn)行時(shí)期的問題ClassCastException問題轉(zhuǎn)換成了編譯失敗,體現(xiàn)在編譯時(shí)期,程序員就可以解決問題。
2:避免了強(qiáng)制轉(zhuǎn)換的麻煩。
只要帶有<>的類或者接口,都屬于帶有類型參數(shù)的類或者接口,在使用這些類或者接口時(shí),必須給<>中傳遞一個(gè)具體的引用數(shù)據(jù)類型。
泛型技術(shù):其實(shí)應(yīng)用在編譯時(shí)期,是給編譯器使用的技術(shù),到了運(yùn)行時(shí)期,泛型就不存在了。
為什么? 因?yàn)?strong>泛型的擦除:也就是說,編輯器檢查了泛型的類型正確后,在生成的類文件中是沒有泛型的。
在運(yùn)行時(shí),如何知道獲取的元素類型而不用強(qiáng)轉(zhuǎn)呢?
泛型的補(bǔ)償:因?yàn)榇鎯Φ臅r(shí)候,類型已經(jīng)確定了是同一個(gè)類型的元素,所以在運(yùn)行時(shí),只要獲取到該元素的類型,在內(nèi)部進(jìn)行一次轉(zhuǎn)換即可,所以使用者不用再做轉(zhuǎn)換動(dòng)作了。
什么時(shí)候用泛型類呢?
當(dāng)類中的操作的引用數(shù)據(jù)類型不確定的時(shí)候,以前用的Object來進(jìn)行擴(kuò)展的,現(xiàn)在可以用泛型來表示。這樣可以避免強(qiáng)轉(zhuǎn)的麻煩,而且將運(yùn)行問題轉(zhuǎn)移到的編譯時(shí)期。
----------------------------------------------------------
泛型在程序定義上的體現(xiàn):
//泛型類:將泛型定義在類上。
class Tool<Q> {
private Q obj;
public void setObject(Q obj) {
this.obj = obj;
}
public Q getObject() {
return obj;
}
}
//當(dāng)方法操作的引用數(shù)據(jù)類型不確定的時(shí)候,可以將泛型定義在方法上。
public <W> void method(W w) {
System.out.println("method:"+w);
}
//靜態(tài)方法上的泛型:靜態(tài)方法無法訪問類上定義的泛型。如果靜態(tài)方法操作的引用數(shù)據(jù)類型不確定的時(shí)候,必須要將泛型定義在方法上。
public static <Q> void function(Q t) {
System.out.println("function:"+t);
}
//泛型接口.
interface Inter<T> {
void show(T t);
}
class InterImpl<R> implements Inter<R> {
public void show(R r) {
System.out.println("show:"+r);
}
}
------------------------------------------------------------
泛型中的通配符:可以解決當(dāng)具體類型不確定的時(shí)候,這個(gè)通配符就是 ? ;當(dāng)操作類型時(shí),不需要使用類型的具體功能時(shí),只使用Object類中的功能。那么可以用 ? 通配符來表未知類型。
泛型限定:
上限:?extends E:可以接收E類型或者E的子類型對象。
下限:?super E:可以接收E類型或者E的父類型對象。
上限什么時(shí)候用:往集合中添加元素時(shí),既可以添加E類型對象,又可以添加E的子類型對象。為什么?因?yàn)槿〉臅r(shí)候,E類型既可以接收E類對象,又可以接收E的子類型對象。
下限什么時(shí)候用:當(dāng)從集合中獲取元素進(jìn)行操作的時(shí)候,可以用當(dāng)前元素的類型接收,也可以用當(dāng)前元素的父類型接收。
泛型的細(xì)節(jié):
1)、泛型到底代表什么類型取決于調(diào)用者傳入的類型,如果沒傳,默認(rèn)是Object類型;
2)、使用帶泛型的類創(chuàng)建對象時(shí),等式兩邊指定的泛型必須一致;
原因:編譯器檢查對象調(diào)用方法時(shí)只看變量,然而程序運(yùn)行期間調(diào)用方法時(shí)就要考慮對象具體類型了;
3)、等式兩邊可以在任意一邊使用泛型,在另一邊不使用(考慮向后兼容);
ArrayList<String> al = new ArrayList<Object>(); //錯(cuò)
//要保證左右兩邊的泛型具體類型一致就可以了,這樣不容易出錯(cuò)。
ArrayList<? extends Object> al = new ArrayList<String>();
al.add("aa"); //錯(cuò)
//因?yàn)榧暇唧w對象中既可存儲String,也可以存儲Object的其他子類,所以添加具體的類型對象不合適,類型檢查會出現(xiàn)安全問題。 ?extends Object 代表Object的子類型不確定,怎么能添加具體類型的對象呢?
public static void method(ArrayList<? extends Object> al) {
al.add("abc"); //錯(cuò)
//只能對al集合中的元素調(diào)用Object類中的方法,具體子類型的方法都不能用,因?yàn)樽宇愋筒淮_定。
}
------------------------------------------------------------------------------------------------------------------------------------------------
API--- java.lang.System: 屬性和行為都是靜態(tài)的。
long currentTimeMillis(); // 返回當(dāng)前時(shí)間毫秒值
exit(); // 退出虛擬機(jī)
Properties getProperties() ; // 獲取當(dāng)前系統(tǒng)的屬性信息
Properties prop = System.getProperties(); //獲取系統(tǒng)的屬性信息,并將這些信息存儲到Properties集合中。
System.setProperty("myname","畢老師"); //給系統(tǒng)屬性信息集添加具體的屬性信息
//臨時(shí)設(shè)置方式:運(yùn)行jvm時(shí),可以通過jvm的參數(shù)進(jìn)行系統(tǒng)屬性的臨時(shí)設(shè)置,可以在java命令的后面加入 –D<name>=<value> 用法:java –Dmyname=小明 類名。
String name = System.getProperty("os.name");//獲取指定屬性的信息
//想要知道該系統(tǒng)是否是該軟件所支持的系統(tǒng)中的一個(gè)。
Set<String> hs = new HashSet<String>();
hs.add("Windows XP");
hs.add("Windows 7");
if(hs.contains(name))
System.out.println("可以支持");
else
System.out.println("不支持");
--------------------------------------------------------------------------------------------------------------------
API--- java.lang.Runtime: 類中沒有構(gòu)造方法,不能創(chuàng)建對象。
但是有非靜態(tài)方法。說明該類中應(yīng)該定義好了對象,并可以通過一個(gè)static方法獲取這個(gè)對象。用這個(gè)對象來調(diào)用非靜態(tài)方法。這個(gè)方法就是 static Runtime getRuntime();
這個(gè)Runtime其實(shí)使用單例設(shè)計(jì)模式進(jìn)行設(shè)計(jì)。
class RuntimeDemo {
public static void main(String[] args) throws Exception {
Runtime r = Runtime.getRuntime();
Process p = r.exec("notepad.exe SystemDemo.java"); //運(yùn)行指定的程序
Thread.sleep(4000);
p.destroy(); //殺掉進(jìn)程
}
}
--------------------------------------------------------------------------------------------------------------------
API--- java.util.Math: 用于數(shù)學(xué)運(yùn)算的工具類,屬性和行為都是靜態(tài)的。該類是final不允許繼承。
static double ceil(double a) ; //返回大于指定數(shù)值的最小整數(shù)
static double floor(double a) ; //返回小于指定數(shù)值的最大整數(shù)
static long round(double a) ; //四舍五入成整數(shù)
static double pow(double a, double b) ; //a的b次冪
static double random(); //返回0~1的偽隨機(jī)數(shù)
public static void main(String[] args) {
Random r = new Random();
for(int x=0; x<10; x++) {
//double d = Math.floor(Math.random()*10+1);
//int d = (int)(Math.random()*10+1);
int d = r.nextInt(10)+1;
System.out.println(d);
}
}
--------------------------------------------------------------------------------------------------------------------
API--- java.util.Date:日期類,月份從0-11;
/*
日期對象和毫秒值之間的轉(zhuǎn)換。
1,日期對象轉(zhuǎn)成毫秒值。Date類中的getTime方法。
2,如何將獲取到的毫秒值轉(zhuǎn)成具體的日期呢?
Date類中的setTime方法。也可以通過構(gòu)造函數(shù)。
*/
//日期對象轉(zhuǎn)成毫秒值
Date d = new Date();
long time1 = d.getTime();
long time2 = System.currentTimeMillis(); / /毫秒值。
//毫秒值轉(zhuǎn)成具體的日期
long time = 1322709921312l;
Date d = new Date();
d.setTime(time);
/*
將日期字符串轉(zhuǎn)換成日期對象:使用的就是DateFormat方法中的 Date parse(String source) ;
*/
public static void method() throws Exception {
String str_time = "2011/10/25";
DateFormat df = new SimpleDateFormat("yyyy/MM/dd"); //SimpleDateFormat作為可以指定用戶自定義的格式來完成格式化。
Date d = df.parse(str_time);
}
/*
如果不需要使用特定的格式化風(fēng)格,完全可以使用DateFormat類中的靜態(tài)工廠方法獲取具體的已經(jīng)封裝好風(fēng)格的對象。getDateInstance();getDateTimeInstance();
*/
Date d = new Date();
DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
String str_time = df.format(d);
//將日期對象轉(zhuǎn)換成字符串的方式:DateFormat類中的format方法。
//創(chuàng)建日期格式對象。
DateFormat df = new SimpleDateFormat(); //該對象的建立內(nèi)部會封裝一個(gè)默認(rèn)的日期格式。11-12-1 下午1:48
//如果想要自定義日期格式的話??墒褂肧impleDateFormat的構(gòu)造函數(shù)。將具體的格式作為參數(shù)傳入到構(gòu)造函數(shù)中。如何表示日期中年的部分呢?可以必須要參與格式對象文檔。
df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
//調(diào)用DateFormat中的format方法。對已有的日期對象進(jìn)行格式化。
String str_time = df.format(d);
--------------------------------------------------------------------------------------------------------------------
API--- java.util. Calendar:日歷類
public static void method(){
Calendar c = Calendar.getInstance();
System.out.println(c.get(Calendar.YEAR)+"年"+(c.get(Calendar.MONTH)+1)+"月"
+getNum(c.get(Calendar.DAY_OF_MONTH))+"日"
+"星期"+getWeek(c.get(Calendar.DAY_OF_WEEK)));
}
public static String getNum(int num){
return num>9 ? num+"" : "0"+num;
}
public static String getWeek(int index){
/*
查表法:建立數(shù)據(jù)的對應(yīng)關(guān)系.
最好:數(shù)據(jù)個(gè)數(shù)是確定的,而且有對應(yīng)關(guān)系。如果對應(yīng)關(guān)系的一方,是數(shù)字,而且可以作為角標(biāo),那么可以通過數(shù)組來作為表。
*/
String[] weeks = {"","日","一","二","三","四","五","六"};
return weeks[index];
}
------------------------------------------------------------------------------------------------------------------------------------------------
IO流:★★★★★,用于處理設(shè)備上數(shù)據(jù)。
流:可以理解數(shù)據(jù)的流動(dòng),就是一個(gè)數(shù)據(jù)流。IO流最終要以對象來體現(xiàn),對象都存在IO包中。
流也進(jìn)行分類:
1:輸入流(讀)和輸出流(寫)。
2:因?yàn)樘幚淼臄?shù)據(jù)不同,分為字節(jié)流和字符流。
字節(jié)流:處理字節(jié)數(shù)據(jù)的流對象。設(shè)備上的數(shù)據(jù)無論是圖片或者dvd,文字,它們都以二進(jìn)制存儲的。二進(jìn)制的最終都是以一個(gè)8位為數(shù)據(jù)單元進(jìn)行體現(xiàn),所以計(jì)算機(jī)中的最小數(shù)據(jù)單元就是字節(jié)。意味著,字節(jié)流可以處理設(shè)備上的所有數(shù)據(jù),所以字節(jié)流一樣可以處理字符數(shù)據(jù)。
那么為什么要有字符流呢?因?yàn)樽址總€(gè)國家都不一樣,所以涉及到了字符編碼問題,那么GBK編碼的中文用unicode編碼解析是有問題的,所以需要獲取中文字節(jié)數(shù)據(jù)的同時(shí)+ 指定的編碼表才可以解析正確數(shù)據(jù)。為了方便于文字的解析,所以將字節(jié)流和編碼表封裝成對象,這個(gè)對象就是字符流。只要操作字符數(shù)據(jù),優(yōu)先考慮使用字符流體系。
注意:流的操作只有兩種:讀和寫。
流的體系因?yàn)楣δ懿煌怯泄残詢?nèi)容,不斷抽取,形成繼承體系。該體系一共有四個(gè)基類,而且都是抽象類。
字節(jié)流:InputStream OutputStream
字符流:Reader Writer
在這四個(gè)系統(tǒng)中,它們的子類,都有一個(gè)共性特點(diǎn):子類名后綴都是父類名,前綴名都是這個(gè)子類的功能名稱。
--------------------------------------------------------------------------------------------------------------------
public static void main(String[] args) throws IOException { //讀、寫都會發(fā)生IO異常
/*
1:創(chuàng)建一個(gè)字符輸出流對象,用于操作文件。該對象一建立,就必須明確數(shù)據(jù)存儲位置,是一個(gè)文件。
2:對象產(chǎn)生后,會在堆內(nèi)存中有一個(gè)實(shí)體,同時(shí)也調(diào)用了系統(tǒng)底層資源,在指定的位置創(chuàng)建了一個(gè)存儲數(shù)據(jù)的文件。
3:如果指定位置,出現(xiàn)了同名文件,文件會被覆蓋。
*/
FileWriter fw = new FileWriter("demo.txt"); // FileNotFoundException
/*
調(diào)用Writer類中的write方法寫入字符串。字符串并未直接寫入到目的地中,而是寫入到了流中,(其實(shí)是寫入到內(nèi)存緩沖區(qū)中)。怎么把數(shù)據(jù)弄到文件中?
*/
fw.write("abcde");
fw.flush(); // 刷新緩沖區(qū),將緩沖區(qū)中的數(shù)據(jù)刷到目的地文件中。
fw.close(); // 關(guān)閉流,其實(shí)關(guān)閉的就是java調(diào)用的系統(tǒng)底層資源。在關(guān)閉前,會先刷新該流。
}
close()和flush()的區(qū)別:
flush():將緩沖區(qū)的數(shù)據(jù)刷到目的地中后,流可以使用。
close():將緩沖區(qū)的數(shù)據(jù)刷到目的地中后,流就關(guān)閉了,該方法主要用于結(jié)束調(diào)用的底層資源。這個(gè)動(dòng)作一定做。
--------------------------------------------------------------------------------------------------------------------
io異常的處理方式:io一定要寫finally;
FileWriter寫入數(shù)據(jù)的細(xì)節(jié):
1:window中的換行符:\r\n兩個(gè)符號組成。 linux:\n。
2:續(xù)寫數(shù)據(jù),只要在構(gòu)造函數(shù)中傳入新的參數(shù)true。
3:目錄分割符:window \\ /
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt",true);
fw.write("abcde");
}
catch (IOException e ){
System.out.println(e.toString()+"....");
}
finally{
if(fw!=null)
try{
fw.close();
}
catch (IOException e){
System.out.println("close:"+e.toString());
}
}
}
--------------------------------------------------------------------------------------------------------------------
FileReader:使用Reader體系,讀取一個(gè)文本文件中的數(shù)據(jù)。返回 -1 ,標(biāo)志讀到結(jié)尾。
import java.io.*;
class FileReaderDemo {
public static void main(String[] args) throws IOException {
/*
創(chuàng)建可以讀取文本文件的流對象,FileReader讓創(chuàng)建好的流對象和指定的文件相關(guān)聯(lián)。
*/
FileReader fr = new FileReader("demo.txt");
int ch = 0;
while((ch = fr.read())!= -1) { //條件是沒有讀到結(jié)尾
System.out.println((char)ch); //調(diào)用讀取流的read方法,讀取一個(gè)字符。
}
fr.close();
}
}
--------------------------------------------------------------------------------------------------------------------
讀取數(shù)據(jù)的第二種方式:第二種方式較為高效,自定義緩沖區(qū)。
import java.io.*;
class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt"); //創(chuàng)建讀取流對象和指定文件關(guān)聯(lián)。
//因?yàn)橐褂胷ead(char[])方法,將讀取到字符存入數(shù)組。所以要?jiǎng)?chuàng)建一個(gè)字符數(shù)組,一般數(shù)組的長度都是1024的整數(shù)倍。
char[] buf = new char[1024];
int len = 0;
while(( len=fr.read(buf)) != -1) {
System.out.println(new String(buf,0,len));
}
fr.close();
}
}
--------------------------------------------------------------------------------------------------------------------
IO中的使用到了一個(gè)設(shè)計(jì)模式:裝飾設(shè)計(jì)模式。
裝飾設(shè)計(jì)模式解決:對一組類進(jìn)行功能的增強(qiáng)。
包裝:寫一個(gè)類(包裝類)對被包裝對象進(jìn)行包裝;
* 1、包裝類和被包裝對象要實(shí)現(xiàn)同樣的接口;
* 2、包裝類要持有一個(gè)被包裝對象;
* 3、包裝類在實(shí)現(xiàn)接口時(shí),大部分方法是靠調(diào)用被包裝對象來實(shí)現(xiàn)的,對于需要修改的方法我們自己實(shí)現(xiàn);
--------------------------------------------------------------------------------------------------------------------
字符流:
Reader:用于讀取字符流的抽象類。子類必須實(shí)現(xiàn)的方法只有 read(char[], int, int) 和 close()。
|---BufferedReader:從字符輸入流中讀取文本,緩沖各個(gè)字符,從而實(shí)現(xiàn)字符、數(shù)組和行的高效讀取。 可以指定緩沖區(qū)的大小,或者可使用默認(rèn)的大小。大多數(shù)情況下,默認(rèn)值就足夠大了。
|---LineNumberReader:跟蹤行號的緩沖字符輸入流。此類定義了方法 setLineNumber(int) 和 getLineNumber(),它們可分別用于設(shè)置和獲取當(dāng)前行號。
|---InputStreamReader:是字節(jié)流通向字符流的橋梁:它使用指定的 charset 讀取字節(jié)并將其解碼為字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺默認(rèn)的字符集。
|---FileReader:用來讀取字符文件的便捷類。此類的構(gòu)造方法假定默認(rèn)字符編碼和默認(rèn)字節(jié)緩沖區(qū)大小都是適當(dāng)?shù)?。要自己指定這些值,可以先在 FileInputStream 上構(gòu)造一個(gè) InputStreamReader。
|---CharArrayReader:
|---StringReader:
-------------------------------------------------
Writer:寫入字符流的抽象類。子類必須實(shí)現(xiàn)的方法僅有 write(char[], int, int)、flush() 和 close()。
|---BufferedWriter:將文本寫入字符輸出流,緩沖各個(gè)字符,從而提供單個(gè)字符、數(shù)組和字符串的高效寫入。
|---OutputStreamWriter:是字符流通向字節(jié)流的橋梁:可使用指定的 charset 將要寫入流中的字符編碼成字節(jié)。它使用的字符集可以由名稱指定或顯式給定,否則將接受平臺默認(rèn)的字符集。
|---FileWriter:用來寫入字符文件的便捷類。此類的構(gòu)造方法假定默認(rèn)字符編碼和默認(rèn)字節(jié)緩沖區(qū)大小都是可接受的。要自己指定這些值,可以先在 FileOutputStream 上構(gòu)造一個(gè) OutputStreamWriter。
|---PrintWriter:
|---CharArrayWriter:
|---StringWriter:
---------------------------------
字節(jié)流:
InputStream:是表示字節(jié)輸入流的所有類的超類。
|--- FileInputStream:從文件系統(tǒng)中的某個(gè)文件中獲得輸入字節(jié)。哪些文件可用取決于主機(jī)環(huán)境。FileInputStream 用于讀取諸如圖像數(shù)據(jù)之類的原始字節(jié)流。要讀取字符流,請考慮使用 FileReader。
|--- FilterInputStream:包含其他一些輸入流,它將這些流用作其基本數(shù)據(jù)源,它可以直接傳輸數(shù)據(jù)或提供一些額外的功能。
|--- BufferedInputStream:該類實(shí)現(xiàn)緩沖的輸入流。
|--- Stream:
|--- ObjectInputStream:
|--- PipedInputStream:
-----------------------------------------------
OutputStream:此抽象類是表示輸出字節(jié)流的所有類的超類。
|--- FileOutputStream:文件輸出流是用于將數(shù)據(jù)寫入 File 或 FileDescriptor 的輸出流。
|--- FilterOutputStream:此類是過濾輸出流的所有類的超類。
|--- BufferedOutputStream:該類實(shí)現(xiàn)緩沖的輸出流。
|--- PrintStream:
|--- DataOutputStream:
|--- ObjectOutputStream:
|--- PipedOutputStream:
--------------------------------
緩沖區(qū)是提高效率用的,給誰提高呢?
BufferedWriter:是給字符輸出流提高效率用的,那就意味著,緩沖區(qū)對象建立時(shí),必須要先有流對象。明確要提高具體的流對象的效率。
FileWriter fw = new FileWriter("bufdemo.txt");
BufferedWriter bufw = new BufferedWriter(fw);//讓緩沖區(qū)和指定流相關(guān)聯(lián)。
for(int x=0; x<4; x++){
bufw.write(x+"abc");
bufw.newLine(); //寫入一個(gè)換行符,這個(gè)換行符可以依據(jù)平臺的不同寫入不同的換行符。
bufw.flush();//對緩沖區(qū)進(jìn)行刷新,可以讓數(shù)據(jù)到目的地中。
}
bufw.close();//關(guān)閉緩沖區(qū),其實(shí)就是在關(guān)閉具體的流。
-----------------------------
BufferedReader:
FileReader fr = new FileReader("bufdemo.txt");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line=bufr.readLine())!=null){ //readLine方法返回的時(shí)候是不帶換行符的。
System.out.println(line);
}
bufr.close();
-----------------------------
//記住,只要一讀取鍵盤錄入,就用這句話。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));//輸出到控制臺
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());//將輸入的字符轉(zhuǎn)成大寫字符輸出
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
------------------------------
流對象:其實(shí)很簡單,就是讀取和寫入。但是因?yàn)楣δ艿牟煌?,流的體系中提供N多的對象。那么開始時(shí),到底該用哪個(gè)對象更為合適呢?這就需要明確流的操作規(guī)律。
流的操作規(guī)律:
1,明確源和目的。
數(shù)據(jù)源:就是需要讀取,可以使用兩個(gè)體系:InputStream、Reader;
數(shù)據(jù)匯:就是需要寫入,可以使用兩個(gè)體系:OutputStream、Writer;
2,操作的數(shù)據(jù)是否是純文本數(shù)據(jù)?
如果是:數(shù)據(jù)源:Reader
數(shù)據(jù)匯:Writer
如果不是:數(shù)據(jù)源:InputStream
數(shù)據(jù)匯:OutputStream
3,雖然確定了一個(gè)體系,但是該體系中有太多的對象,到底用哪個(gè)呢?
明確操作的數(shù)據(jù)設(shè)備。
數(shù)據(jù)源對應(yīng)的設(shè)備:硬盤(File),內(nèi)存(數(shù)組),鍵盤(System.in)
數(shù)據(jù)匯對應(yīng)的設(shè)備:硬盤(File),內(nèi)存(數(shù)組),控制臺(System.out)。
4,需要在基本操作上附加其他功能嗎?比如緩沖。
如果需要就進(jìn)行裝飾。
轉(zhuǎn)換流特有功能:轉(zhuǎn)換流可以將字節(jié)轉(zhuǎn)成字符,原因在于,將獲取到的字節(jié)通過查編碼表獲取到指定對應(yīng)字符。
轉(zhuǎn)換流的最強(qiáng)功能就是基于 字節(jié)流 + 編碼表 。沒有轉(zhuǎn)換,沒有字符流。
發(fā)現(xiàn)轉(zhuǎn)換流有一個(gè)子類就是操作文件的字符流對象:
InputStreamReader
|--FileReader
OutputStreamWriter
|--FileWrier
想要操作文本文件,必須要進(jìn)行編碼轉(zhuǎn)換,而編碼轉(zhuǎn)換動(dòng)作轉(zhuǎn)換流都完成了。所以操作文件的流對象只要繼承自轉(zhuǎn)換流就可以讀取一個(gè)字符了。
但是子類有一個(gè)局限性,就是子類中使用的編碼是固定的,是本機(jī)默認(rèn)的編碼表,對于簡體中文版的系統(tǒng)默認(rèn)碼表是GBK。
FileReader fr = new FileReader("a.txt");
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk");
以上兩句代碼功能一致,
如果僅僅使用平臺默認(rèn)碼表,就使用FileReader fr = new FileReader("a.txt"); //因?yàn)楹喕?/p>
如果需要制定碼表,必須用轉(zhuǎn)換流。
轉(zhuǎn)換流 = 字節(jié)流+編碼表。
轉(zhuǎn)換流的子類File = 字節(jié)流 + 默認(rèn)編碼表。
凡是操作設(shè)備上的文本數(shù)據(jù),涉及編碼轉(zhuǎn)換,必須使用轉(zhuǎn)換流。
-----------------------------------------------------------------------------------------------
File類:將文件系統(tǒng)中的文件和文件夾封裝成了對象。提供了更多的屬性和行為可以對這些文件和文件夾進(jìn)行操作。這些是流對象辦不到的,因?yàn)榱髦徊僮鲾?shù)據(jù)。
File類常見方法:
1:創(chuàng)建。
boolean createNewFile():在指定目錄下創(chuàng)建文件,如果該文件已存在,則不創(chuàng)建。而對操作文件的輸出流而言,輸出流對象已建立,就會創(chuàng)建文件,如果文件已存在,會覆蓋。除非續(xù)寫。
boolean mkdir():創(chuàng)建此抽象路徑名指定的目錄。
boolean mkdirs():創(chuàng)建多級目錄。
2:刪除。
boolean delete():刪除此抽象路徑名表示的文件或目錄。
void deleteOnExit():在虛擬機(jī)退出時(shí)刪除。
注意:在刪除文件夾時(shí),必須保證這個(gè)文件夾中沒有任何內(nèi)容,才可以將該文件夾用delete刪除。
window的刪除動(dòng)作,是從里往外刪。注意:java刪除文件不走回收站。要慎用。
3:獲取.
long length():獲取文件大小。
String getName():返回由此抽象路徑名表示的文件或目錄的名稱。
String getPath():將此抽象路徑名轉(zhuǎn)換為一個(gè)路徑名字符串。
String getAbsolutePath():返回此抽象路徑名的絕對路徑名字符串。
String getParent():返回此抽象路徑名父目錄的抽象路徑名,如果此路徑名沒有指定父目錄,則返回 null。
long lastModified():返回此抽象路徑名表示的文件最后一次被修改的時(shí)間。
File.pathSeparator:返回當(dāng)前系統(tǒng)默認(rèn)的路徑分隔符,windows默認(rèn)為 “;”。
File.Separator:返回當(dāng)前系統(tǒng)默認(rèn)的目錄分隔符,windows默認(rèn)為 “\”。
4:判斷:
boolean exists():判斷文件或者文件夾是否存在。
boolean isDirectory():測試此抽象路徑名表示的文件是否是一個(gè)目錄。
boolean isFile():測試此抽象路徑名表示的文件是否是一個(gè)標(biāo)準(zhǔn)文件。
boolean isHidden():測試此抽象路徑名指定的文件是否是一個(gè)隱藏文件。
boolean isAbsolute():測試此抽象路徑名是否為絕對路徑名。
5:重命名。
boolean renameTo(File dest):可以實(shí)現(xiàn)移動(dòng)的效果。剪切+重命名。
String[] list():列出指定目錄下的當(dāng)前的文件和文件夾的名稱。包含隱藏文件。
如果調(diào)用list方法的File 對象中封裝的是一個(gè)文件,那么list方法返回?cái)?shù)組為null。如果封裝的對象不存在也會返回null。只有封裝的對象存在并且是文件夾時(shí),這個(gè)方法才有效。
------------------------------------------------------------------------------------------------
遞歸:就是函數(shù)自身調(diào)用自身。
什么時(shí)候用遞歸呢?
當(dāng)一個(gè)功能被重復(fù)使用,而每一次使用該功能時(shí)的參數(shù)不確定,都由上次的功能元素結(jié)果來確定。
簡單說:功能內(nèi)部又用到該功能,但是傳遞的參數(shù)值不確定。(每次功能參與運(yùn)算的未知內(nèi)容不確定)。
遞歸的注意事項(xiàng):
1:一定要定義遞歸的條件。
2:遞歸的次數(shù)不要過多。容易出現(xiàn) StackOverflowError 棧內(nèi)存溢出錯(cuò)誤。
其實(shí)遞歸就是在棧內(nèi)存中不斷的加載同一個(gè)函數(shù)。
------------------------------------------------------------------------------------------------
Java.util.Properties:一個(gè)可以將鍵值進(jìn)行持久化存儲的對象。Map--Hashtable的子類。
Map
|--Hashtable
|--Properties:用于屬性配置文件,鍵和值都是字符串類型。
特點(diǎn):1:可以持久化存儲數(shù)據(jù)。2:鍵值都是字符串。3:一般用于配置文件。
|-- load():將流中的數(shù)據(jù)加載進(jìn)集合。
原理:其實(shí)就是將讀取流和指定文件相關(guān)聯(lián),并讀取一行數(shù)據(jù),因?yàn)閿?shù)據(jù)是規(guī)則的key=value,所以獲取一行后,通過 = 對該行數(shù)據(jù)進(jìn)行切割,左邊就是鍵,右邊就是值,將鍵、值存儲到properties集合中。
|-- store():寫入各個(gè)項(xiàng)后,刷新輸出流。
|-- list():將集合的鍵值數(shù)據(jù)列出到指定的目的地。
-------------------------------------------------------------------------------------------------
以下介紹IO包中擴(kuò)展功能的流對象:基本都是裝飾設(shè)計(jì)模式。
Java.io.outputstream.PrintStream:打印流
1:提供了更多的功能,比如打印方法??梢灾苯哟蛴∪我忸愋偷臄?shù)據(jù)。
2:它有一個(gè)自動(dòng)刷新機(jī)制,創(chuàng)建該對象,指定參數(shù),對于指定方法可以自動(dòng)刷新。
3:它使用的本機(jī)默認(rèn)的字符編碼.
4:該流的print方法不拋出IOException。
該對象的構(gòu)造函數(shù)。
PrintStream(File file) :創(chuàng)建具有指定文件且不帶自動(dòng)行刷新的新打印流。
PrintStream(File file, String csn) :創(chuàng)建具有指定文件名稱和字符集且不帶自動(dòng)行刷新的新打印流。
PrintStream(OutputStream out) :創(chuàng)建新的打印流。
PrintStream(OutputStream out, boolean autoFlush) :創(chuàng)建新的打印流。
PrintStream(OutputStream out, boolean autoFlush, String encoding) :創(chuàng)建新的打印流。
PrintStream(String fileName) :創(chuàng)建具有指定文件名稱且不帶自動(dòng)行刷新的新打印流。
PrintStream(String fileName, String csn)
PrintStream可以操作目的:1:File對象。2:字符串路徑。3:字節(jié)輸出流。
前兩個(gè)都JDK1.5版本才出現(xiàn)。而且在操作文本文件時(shí),可指定字符編碼了。
當(dāng)目的是一個(gè)字節(jié)輸出流時(shí),如果使用的println方法,可以在printStream對象上加入一個(gè)true參數(shù)。這樣對于println方法可以進(jìn)行自動(dòng)的刷新,而不是等待緩沖區(qū)滿了再刷新。最終print方法都將具體的數(shù)據(jù)轉(zhuǎn)成字符串,而且都對IO異常進(jìn)行了內(nèi)部處理。
既然操作的數(shù)據(jù)都轉(zhuǎn)成了字符串,那么使用PrintWriter更好一些。因?yàn)镻rintWrite是字符流的子類,可以直接操作字符數(shù)據(jù),同時(shí)也可以指定具體的編碼。
--------------------------------------------------------
PrintWriter:具備了PrintStream的特點(diǎn)同時(shí),還有自身特點(diǎn):
該對象的目的地有四個(gè):1:File對象。2:字符串路徑。3:字節(jié)輸出流。4:字符輸出流。
開發(fā)時(shí)盡量使用PrintWriter。
方法中直接操作文件的第二參數(shù)是編碼表。
直接操作輸出流的,第二參數(shù)是自動(dòng)刷新。
//讀取鍵盤錄入將數(shù)據(jù)轉(zhuǎn)成大寫顯示在控制臺.
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//源:鍵盤輸入
//目的:把數(shù)據(jù)寫到文件中,還想自動(dòng)刷新。
PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);//設(shè)置true后自動(dòng)刷新
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
out.println(line.toUpperCase());//轉(zhuǎn)大寫輸出
}
//注意:System.in,System.out這兩個(gè)標(biāo)準(zhǔn)的輸入輸出流,在jvm啟動(dòng)時(shí)已經(jīng)存在了。隨時(shí)可以使用。當(dāng)jvm結(jié)束了,這兩個(gè)流就結(jié)束了。但是,當(dāng)使用了顯示的close方法關(guān)閉時(shí),這兩個(gè)流在提前結(jié)束了。
out.close();
bufr.close();
------------------------------------------------------------------------------------------------
SequenceInputStream:序列流,作用就是將多個(gè)讀取流合并成一個(gè)讀取流。實(shí)現(xiàn)數(shù)據(jù)合并。
表示其他輸入流的邏輯串聯(lián)。它從輸入流的有序集合開始,并從第一個(gè)輸入流開始讀取,直到到達(dá)文件末尾,接著從第二個(gè)輸入流讀取,依次類推,直到到達(dá)包含的最后一個(gè)輸入流的文件末尾為止。
這樣做,可以更方便的操作多個(gè)讀取流,其實(shí)這個(gè)序列流內(nèi)部會有一個(gè)有序的集合容器,用于存儲多個(gè)讀取流對象。
該對象的構(gòu)造函數(shù)參數(shù)是枚舉,想要獲取枚舉,需要有Vector集合,但不高效。需用ArrayList,但ArrayList中沒有枚舉,只有自己去創(chuàng)建枚舉對象。
但是方法怎么實(shí)現(xiàn)呢?因?yàn)槊杜e操作的是具體集合中的元素,所以無法具體實(shí)現(xiàn),但是枚舉和迭代器是功能一樣的,所以,可以用迭代替代枚舉。
合并原理:多個(gè)讀取流對應(yīng)一個(gè)輸出流。
切割原理:一個(gè)讀取流對應(yīng)多個(gè)輸出流。
import java.io.*;
import java.util.*;
class SplitFileDemo{
private static final String CFG = ".properties";
private static final String SP = ".part";
public static void main(String[] args) throws IOException{
File file = new File("c:\\0.bmp");
File dir = new File("c:\\partfiles");
meger(dir);
}
//數(shù)據(jù)的合并。
public static void meger(File dir)throws IOException{
if(!(dir.exists() && dir.isDirectory()))
throw new RuntimeException("指定的目錄不存在,或者不是正確的目錄");
File[] files = dir.listFiles(new SuffixFilter(CFG));
if(files.length==0)
throw new RuntimeException("擴(kuò)展名.proerpties的文件不存在");
//獲取到配置文件
File config = files[0];
//獲取配置文件的信息。
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(config);
prop.load(fis);
String fileName = prop.getProperty("filename");
int partcount = Integer.parseInt(prop.getProperty("partcount"));
//--------------------------
File[] partFiles = dir.listFiles(new SuffixFilter(SP));
if(partFiles.length!=partcount)
throw new RuntimeException("缺少碎片文件");
//---------------------
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=0; x<partcount; x++){
al.add(new FileInputStream(new File(dir,x+SP)));
}
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
File file = new File(dir,fileName);
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
//帶有配置信息的數(shù)據(jù)切割。
public static void splitFile(File file)throws IOException{
//用一個(gè)讀取流和文件關(guān)聯(lián)。
FileInputStream fis = new FileInputStream(file);
//創(chuàng)建目的地。因?yàn)橛卸鄠€(gè)。所以先創(chuàng)建引用。
FileOutputStream fos = null;
//指定碎片的位置。
File dir = new File("c:\\partfiles");
if(!dir.exists())
dir.mkdir();
//碎片文件大小引用。
File f = null;
byte[] buf = new byte[1024*1024];
//因?yàn)榍懈钔甑奈募ǔ6加幸?guī)律的。為了簡單標(biāo)記規(guī)律使用計(jì)數(shù)器。
int count = 0;
int len = 0;
while((len=fis.read(buf))!=-1){
f = new File(dir,(count++)+".part");
fos = new FileOutputStream(f);
fos.write(buf,0,len);
fos.close();
}
//碎片文件生成后,還需要定義配置文件記錄生成的碎片文件個(gè)數(shù)。以及被切割文件的名稱。
//定義簡單的鍵值信息,可是用Properties。
String filename = file.getName();
Properties prop = new Properties();
prop.setProperty("filename",filename);
prop.setProperty("partcount",count+"");
File config = new File(dir,count+".properties");
fos = new FileOutputStream(config);
prop.store(fos,"");
fos.close();
fis.close();
}
}
class SuffixFilter implements FileFilter{
private String suffix;
SuffixFilter(String suffix){
this.suffix = suffix;
}
public boolean accept(File file){
return file.getName().endsWith(suffix);
}
}
-----------------------------------------------------------------------------------------------
RandomAccessFile:
特點(diǎn):
1:該對象即可讀取,又可寫入。
2:該對象中的定義了一個(gè)大型的byte數(shù)組,通過定義指針來操作這個(gè)數(shù)組。
3:可以通過該對象的getFilePointer()獲取指針的位置,通過seek()方法設(shè)置指針的位置。
4:該對象操作的源和目的必須是文件。
5:其實(shí)該對象內(nèi)部封裝了字節(jié)讀取流和字節(jié)寫入流。
注意:實(shí)現(xiàn)隨機(jī)訪問,最好是數(shù)據(jù)有規(guī)律。
class RandomAccessFileDemo{
public static void main(String[] args) throws IOException{
write();
read();
randomWrite();
}
//隨機(jī)寫入數(shù)據(jù),可以實(shí)現(xiàn)已有數(shù)據(jù)的修改。
public static void randomWrite()throws IOException{
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
raf.seek(8*4);
System.out.println("pos :"+raf.getFilePointer());
raf.write("王武".getBytes());
raf.writeInt(102);
raf.close();
}
public static void read()throws IOException{
RandomAccessFile raf = new RandomAccessFile("random.txt","r");//只讀模式。
//指定指針的位置。
raf.seek(8*1);//實(shí)現(xiàn)隨機(jī)讀取文件中的數(shù)據(jù)。注意:數(shù)據(jù)最好有規(guī)律。
System.out.println("pos1 :"+raf.getFilePointer());
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println(name+"::"+age);
System.out.println("pos2 :"+raf.getFilePointer());
raf.close();
}
public static void write()throws IOException{
//rw:當(dāng)這個(gè)文件不存在,會創(chuàng)建該文件。當(dāng)文件已存在,不會創(chuàng)建。所以不會像輸出流一樣覆蓋。
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");//rw讀寫模式
//往文件中寫入人的基本信息,姓名,年齡。
raf.write("張三".getBytes());
raf.writeInt(97);
raf.close();
}
}
------------------------------------------------------------------------------------------------
管道流:管道讀取流和管道寫入流可以像管道一樣對接上,管道讀取流就可以讀取管道寫入流寫入的數(shù)據(jù)。
注意:需要加入多線程技術(shù),因?yàn)閱尉€程,先執(zhí)行read,會發(fā)生死鎖,因?yàn)閞ead方法是阻塞式的,沒有數(shù)據(jù)的read方法會讓線程等待。
public static void main(String[] args) throws IOException{
PipedInputStream pipin = new PipedInputStream();
PipedOutputStream pipout = new PipedOutputStream();
pipin.connect(pipout);
new Thread(new Input(pipin)).start();
new Thread(new Output(pipout)).start();
}
------------------------------------------------------------------------------------------------
對象的序列化:目的:將一個(gè)具體的對象進(jìn)行持久化,寫入到硬盤上。
注意:靜態(tài)數(shù)據(jù)不能被序列化,因?yàn)殪o態(tài)數(shù)據(jù)不在堆內(nèi)存中,是存儲在靜態(tài)方法區(qū)中。
如何將非靜態(tài)的數(shù)據(jù)不進(jìn)行序列化?用transient 關(guān)鍵字修飾此變量即可。
Serializable:用于啟動(dòng)對象的序列化功能,可以強(qiáng)制讓指定類具備序列化功能,該接口中沒有成員,這是一個(gè)標(biāo)記接口。這個(gè)標(biāo)記接口用于給序列化類提供UID。這個(gè)uid是依據(jù)類中的成員的數(shù)字簽名進(jìn)行運(yùn)行獲取的。如果不需要自動(dòng)獲取一個(gè)uid,可以在類中,手動(dòng)指定一個(gè)名稱為serialVersionUID id號。依據(jù)編譯器的不同,或者對信息的高度敏感性。最好每一個(gè)序列化的類都進(jìn)行手動(dòng)顯示的UID的指定。
import java.io.*;
class ObjectStreamDemo {
public static void main(String[] args) throws Exception{
writeObj();
readObj();
}
public static void readObj()throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Object obj = ois.readObject();//讀取一個(gè)對象。
System.out.println(obj.toString());
}
public static void writeObj()throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",25)); //寫入一個(gè)對象。
oos.close();
}
}
class Person implements Serializable{
private static final long serialVersionUID = 42L;
private transient String name;//用transient修飾后name將不會進(jìn)行序列化
public int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+"::"+age;
}
}
-----------------------------------------------------------------------------------------------
DataOutputStream、DataInputStream:專門用于操作基本數(shù)據(jù)類型數(shù)據(jù)的對象。
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(256);
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
System.out.println(num);
dis.close();
-----------------------------------------------------------------------------------------------
ByteArrayInputStream:源:內(nèi)存
ByteArrayOutputStream:目的:內(nèi)存。
這兩個(gè)流對象不涉及底層資源調(diào)用,操作的都是內(nèi)存中數(shù)組,所以不需要關(guān)閉。
直接操作字節(jié)數(shù)組就可以了,為什么還要把數(shù)組封裝到流對象中呢?因?yàn)閿?shù)組本身沒有方法,只有一個(gè)length屬性。為了便于數(shù)組的操作,將數(shù)組進(jìn)行封裝,對外提供方法操作數(shù)組中的元素。
對于數(shù)組元素操作無非兩種操作:設(shè)置(寫)和獲?。ㄗx),而這兩操作正好對應(yīng)流的讀寫操作。這兩個(gè)對象就是使用了流的讀寫思想來操作數(shù)組。
//創(chuàng)建源:
ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes());
//創(chuàng)建目的:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1){
bos.write(ch);
}
System.out.println(bos.toString());
-----------------------------------------------------------------------------------------------
網(wǎng)絡(luò)編程:
端口:
物理端口:
邏輯端口:用于標(biāo)識進(jìn)程的邏輯地址,不同進(jìn)程的標(biāo)識;有效端口:0~65535,其中0~1024系統(tǒng)使用或保留端口。
java 中ip對象:InetAddress.
import java.net.*;
class IPDemo{
public static void main(String[] args) throws UnknownHostException{
//通過名稱(ip字符串or主機(jī)名)來獲取一個(gè)ip對象。
InetAddress ip = InetAddress.getByName("www.baidu.com");//java.net.UnknownHostException
System.out.println("addr:"+ip.getHostAddress());
System.out.println("name:"+ip.getHostName());
}
}
Socket:★★★★,套接字,通信的端點(diǎn)。
就是為網(wǎng)絡(luò)服務(wù)提供的一種機(jī)制,通信的兩端都有Socket,網(wǎng)絡(luò)通信其實(shí)就是Socket間的通信,數(shù)據(jù)在兩個(gè)Socket間通過IO傳輸。
UDP傳輸:
1,只要是網(wǎng)絡(luò)傳輸,必須有socket 。
2,數(shù)據(jù)一定要封裝到數(shù)據(jù)包中,數(shù)據(jù)包中包括目的地址、端口、數(shù)據(jù)等信息。
直接操作udp不可能,對于java語言應(yīng)該將udp封裝成對象,易于我們的使用,這個(gè)對象就是DatagramSocket. 封裝了udp傳輸協(xié)議的socket對象。
因?yàn)閿?shù)據(jù)包中包含的信息較多,為了操作這些信息方便,也一樣會將其封裝成對象。這個(gè)數(shù)據(jù)包對象就是:DatagramPacket.通過這個(gè)對象中的方法,就可以獲取到數(shù)據(jù)包中的各種信息。
DatagramSocket具備發(fā)送和接受功能,在進(jìn)行udp傳輸時(shí),需要明確一個(gè)是發(fā)送端,一個(gè)是接收端。
udp的發(fā)送端:
1,建立udp的socket服務(wù),創(chuàng)建對象時(shí)如果沒有明確端口,系統(tǒng)會自動(dòng)分配一個(gè)未被使用的端口。
2,明確要發(fā)送的具體數(shù)據(jù)。
3,將數(shù)據(jù)封裝成了數(shù)據(jù)包。
4,用socket服務(wù)的send方法將數(shù)據(jù)包發(fā)送出去。
5,關(guān)閉資源。
--------------------------------------------------------------
import java.net.*;
class UdpSend{
public static void main(String[] args)throws Exception {
// 1,建立udp的socket服務(wù)。
DatagramSocket ds = new DatagramSocket(8888);//指定發(fā)送端口,不指定系統(tǒng)會隨機(jī)分配。
// 2,明確要發(fā)送的具體數(shù)據(jù)。
String text = "udp傳輸演示 哥們來了";
byte[] buf = text.getBytes();
// 3,將數(shù)據(jù)封裝成了數(shù)據(jù)包。
DatagramPacket dp = new DatagramPacket(buf,
buf.length,InetAddress.getByName("10.1.31.127"),10000);
// 4,用socket服務(wù)的send方法將數(shù)據(jù)包發(fā)送出去。
ds.send(dp);
// 5,關(guān)閉資源。
ds.close();
}
}
-------------------------------------------------------------
udp的接收端:
1,創(chuàng)建udp的socket服務(wù),必須要明確一個(gè)端口,作用在于,只有發(fā)送到這個(gè)端口的數(shù)據(jù)才是這個(gè)接收端可以處理的數(shù)據(jù)。
2,定義數(shù)據(jù)包,用于存儲接收到數(shù)據(jù)。
3,通過socket服務(wù)的接收方法將收到的數(shù)據(jù)存儲到數(shù)據(jù)包中。
4,通過數(shù)據(jù)包的方法獲取數(shù)據(jù)包中的具體數(shù)據(jù)內(nèi)容,比如ip、端口、數(shù)據(jù)等等。
5,關(guān)閉資源。
-------------------------------------------------------------
class UdpRece {
public static void main(String[] args) throws Exception{
// 1,創(chuàng)建udp的socket服務(wù)。
DatagramSocket ds = new DatagramSocket(10000);
// 2,定義數(shù)據(jù)包,用于存儲接收到數(shù)據(jù)。先定義字節(jié)數(shù)組,數(shù)據(jù)包會把數(shù)據(jù)存儲到字節(jié)數(shù)組中。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
// 3,通過socket服務(wù)的接收方法將收到的數(shù)據(jù)存儲到數(shù)據(jù)包中。
ds.receive(dp);//該方法是阻塞式方法。
// 4,通過數(shù)據(jù)包的方法獲取數(shù)據(jù)包中的具體數(shù)據(jù)內(nèi)容,比如ip,端口,數(shù)據(jù)等等。
String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = new String(dp.getData(),0,dp.getLength());//將字節(jié)數(shù)組中的有效部分轉(zhuǎn)成字符串。
System.out.println(ip+":"+port+"--"+text);
// 5,關(guān)閉資源。
ds.close();
}
}
-------------------------------------------------------------
TCP傳輸:兩個(gè)端點(diǎn)的建立連接后會有一個(gè)傳輸數(shù)據(jù)的通道,這通道稱為流,而且是建立在網(wǎng)絡(luò)基礎(chǔ)上的流,稱之為socket流。該流中既有讀取,也有寫入。
tcp的兩個(gè)端點(diǎn):一個(gè)是客戶端,一個(gè)是服務(wù)端。
客戶端:對應(yīng)的對象,Socket
服務(wù)端:對應(yīng)的對象,ServerSocket
TCP客戶端:
1,建立tcp的socket服務(wù),最好明確具體的地址和端口。這個(gè)對象在創(chuàng)建時(shí),就已經(jīng)可以對指定ip和端口進(jìn)行連接(三次握手)。
2,如果連接成功,就意味著通道建立了,socket流就已經(jīng)產(chǎn)生了。只要獲取到socket流中的讀取流和寫入流即可,只要通過getInputStream和getOutputStream就可以獲取兩個(gè)流對象。
3,關(guān)閉資源。
--------------------------------------------------------------
import java.net.*;
import java.io.*;
//需求:客戶端給服務(wù)器端發(fā)送一個(gè)數(shù)據(jù)。
class TcpClient{
public static void main(String[] args) throws Exception{
Socket s = new Socket("10.1.31.69",10002);
OutputStream out = s.getOutputStream();//獲取了socket流中的輸出流對象。
out.write("tcp演示,哥們又來了!".getBytes());
s.close();
}
}
--------------------------------------------------------------
TCP服務(wù)端:
1,創(chuàng)建服務(wù)端socket服務(wù),并監(jiān)聽一個(gè)端口。
2,服務(wù)端為了給客戶端提供服務(wù),獲取客戶端的內(nèi)容,可以通過accept方法獲取連接過來的客戶端對象。
3,可以通過獲取到的socket對象中的socket流和具體的客戶端進(jìn)行通訊。
4,如果通訊結(jié)束,關(guān)閉資源。注意:要先關(guān)客戶端,再關(guān)服務(wù)端。
--------------------------------------------------------------
class TcpServer{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10002);//建立服務(wù)端的socket服務(wù)
Socket s = ss.accept();//獲取客戶端對象
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
// 可以通過獲取到的socket對象中的socket流和具體的客戶端進(jìn)行通訊。
InputStream in = s.getInputStream();//讀取客戶端的數(shù)據(jù),使用客戶端對象的socket讀取流
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
// 如果通訊結(jié)束,關(guān)閉資源。注意:要先關(guān)客戶端,在關(guān)服務(wù)端。
s.close();
ss.close();
}
}
-----------------------------------------------------------------------------------------------
反射技術(shù):其實(shí)就是動(dòng)態(tài)加載一個(gè)指定的類,并獲取該類中的所有的內(nèi)容。而且將字節(jié)碼文件封裝成對象,并將字節(jié)碼文件中的內(nèi)容都封裝成對象,這樣便于操作這些成員。簡單說:反射技術(shù)可以對一個(gè)類進(jìn)行解剖。
反射的好處:大大的增強(qiáng)了程序的擴(kuò)展性。
反射的基本步驟:
1、獲得Class對象,就是獲取到指定的名稱的字節(jié)碼文件對象。
2、實(shí)例化對象,獲得類的屬性、方法或構(gòu)造函數(shù)。
3、訪問屬性、調(diào)用方法、調(diào)用構(gòu)造函數(shù)創(chuàng)建對象。
獲取這個(gè)Class對象,有三種方式:
1:通過每個(gè)對象都具備的方法getClass來獲取。弊端:必須要?jiǎng)?chuàng)建該類對象,才可以調(diào)用getClass方法。
2:每一個(gè)數(shù)據(jù)類型(基本數(shù)據(jù)類型和引用數(shù)據(jù)類型)都有一個(gè)靜態(tài)的屬性class。弊端:必須要先明確該類。
前兩種方式不利于程序的擴(kuò)展,因?yàn)槎夹枰诔绦蚴褂镁唧w的類來完成。
3:使用的Class類中的方法,靜態(tài)的forName方法。
指定什么類名,就獲取什么類字節(jié)碼文件對象,這種方式的擴(kuò)展性最強(qiáng),只要將類名的字符串傳入即可。
// 1. 根據(jù)給定的類名來獲得 用于類加載
String classname = "cn.itcast.reflect.Person";// 來自配置文件
Class clazz = Class.forName(classname);// 此對象代表Person.class
// 2. 如果拿到了對象,不知道是什么類型 用于獲得對象的類型
Object obj = new Person();
Class clazz1 = obj.getClass();// 獲得對象具體的類型
// 3. 如果是明確地獲得某個(gè)類的Class對象 主要用于傳參
Class clazz2 = Person.class;
反射的用法:
1)、需要獲得java類的各個(gè)組成部分,首先需要獲得類的Class對象,獲得Class對象的三種方式:
Class.forName(classname) 用于做類加載
obj.getClass() 用于獲得對象的類型
類名.class 用于獲得指定的類型,傳參用
2)、反射類的成員方法:
Class clazz = Person.class;
Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});
method.invoke();
3)、反射類的構(gòu)造函數(shù):
Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})
con.newInstance(params...)
4)、反射類的屬性:
Field field = clazz.getField(fieldName);
field.setAccessible(true);
field.setObject(value);
獲取了字節(jié)碼文件對象后,最終都需要?jiǎng)?chuàng)建指定類的對象:
創(chuàng)建對象的兩種方式(其實(shí)就是對象在進(jìn)行實(shí)例化時(shí)的初始化方式):
1,調(diào)用空參數(shù)的構(gòu)造函數(shù):使用了Class類中的newInstance()方法。
2,調(diào)用帶參數(shù)的構(gòu)造函數(shù):先要獲取指定參數(shù)列表的構(gòu)造函數(shù)對象,然后通過該構(gòu)造函數(shù)的對象的newInstance(實(shí)際參數(shù)) 進(jìn)行對象的初始化。
綜上所述,第二種方式,必須要先明確具體的構(gòu)造函數(shù)的參數(shù)類型,不便于擴(kuò)展。所以一般情況下,被反射的類,內(nèi)部通常都會提供一個(gè)公有的空參數(shù)的構(gòu)造函數(shù)。
------------------------------------------------------
// 如何生成獲取到字節(jié)碼文件對象的實(shí)例對象。
Class clazz = Class.forName("cn.itcast.bean.Person");//類加載
// 直接獲得指定的類型
clazz = Person.class;
// 根據(jù)對象獲得類型
Object obj = new Person("zhangsan", 19);
clazz = obj.getClass();
Object obj = clazz.newInstance();//該實(shí)例化對象的方法調(diào)用就是指定類中的空參數(shù)構(gòu)造函數(shù),給創(chuàng)建對象進(jìn)行初始化。當(dāng)指定類中沒有空參數(shù)構(gòu)造函數(shù)時(shí),該如何創(chuàng)建該類對象呢?請看method_2();
public static void method_2() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
//既然類中沒有空參數(shù)的構(gòu)造函數(shù),那么只有獲取指定參數(shù)的構(gòu)造函數(shù),用該函數(shù)來進(jìn)行實(shí)例化。
//獲取一個(gè)帶參數(shù)的構(gòu)造器。
Constructor constructor = clazz.getConstructor(String.class,int.class);
//想要對對象進(jìn)行初始化,使用構(gòu)造器的方法newInstance();
Object obj = constructor.newInstance("zhagnsan",30);
//獲取所有構(gòu)造器。
Constructor[] constructors = clazz.getConstructors();//只包含公共的
constructors = clazz.getDeclaredConstructors();//包含私有的
for(Constructor con : constructors) {
System.out.println(con);
}
}
------------------------------------------------------
反射指定類中的方法:
//獲取類中所有的方法。
public static void method_1() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method[] methods = clazz.getMethods();//獲取的是該類中的公有方法和父類中的公有方法。
methods = clazz.getDeclaredMethods();//獲取本類中的方法,包含私有方法。
for(Method method : methods) {
System.out.println(method);
}
}
//獲取指定方法;
public static void method_2() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
//獲取指定名稱的方法。
Method method = clazz.getMethod("show", int.class,String.class);
//想要運(yùn)行指定方法,當(dāng)然是方法對象最清楚,為了讓方法運(yùn)行,調(diào)用方法對象的invoke方法即可,但是方法運(yùn)行必須要明確所屬的對象和具體的實(shí)際參數(shù)。
Object obj = clazz.newInstance();
method.invoke(obj, 39,"hehehe");//執(zhí)行一個(gè)方法
}
//想要運(yùn)行私有方法。
public static void method_3() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
//想要獲取私有方法。必須用getDeclearMethod();
Method method = clazz.getDeclaredMethod("method", null);
// 私有方法不能直接訪問,因?yàn)闄?quán)限不夠。非要訪問,可以通過暴力的方式。
method.setAccessible(true);//一般很少用,因?yàn)樗接芯褪请[藏起來,所以盡量不要訪問。
}
//反射靜態(tài)方法。
public static void method_4() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("function",null);
method.invoke(null,null);
}
------------------------------------------------------------------------------------------------
正則表達(dá)式:★★★☆,其實(shí)是用來操作字符串的一些規(guī)則。
好處:正則的出現(xiàn),對字符串的復(fù)雜操作變得更為簡單。
特點(diǎn):將對字符串操作的代碼用一些符號來表示。只要使用了指定符號,就可以調(diào)用底層的代碼對字符串進(jìn)行操作。符號的出現(xiàn),簡化了代碼的書寫。
弊端:符號的出現(xiàn)雖然簡化了書寫,但是卻降低了閱讀性。
其實(shí)更多是用正則解決字符串操作的問題。
組:用小括號標(biāo)示,每定義一個(gè)小括號,就是一個(gè)組,而且有自動(dòng)編號,從1開始。
只要使用組,對應(yīng)的數(shù)字就是使用該組的內(nèi)容。別忘了,數(shù)組要加\\。
(aaa(wwww(ccc))(eee))技巧,從左括號開始數(shù)即可。有幾個(gè)左括號就是幾組。
常見操作:
1,匹配:其實(shí)用的就是String類中的matches方法。
String reg = "[1-9][0-9]{4,14}";
boolean b = qq.matches(reg);//將正則和字符串關(guān)聯(lián)對字符串進(jìn)行匹配。
2,切割:其實(shí)用的就是String類中的split方法。
3,替換:其實(shí)用的就是String類中的replaceAll();
4,獲取:
1),先要將正則表達(dá)式編譯成正則對象。使用的是Pattern中靜態(tài)方法 compile(regex);
2),通過Pattern對象獲取Matcher對象。
Pattern用于描述正則表達(dá)式,可以對正則表達(dá)式進(jìn)行解析。
而將規(guī)則操作字符串,需要從新封裝到匹配器對象Matcher中。
然后使用Matcher對象的方法來操作字符串。
如何獲取匹配器對象呢?
通過Pattern對象中的matcher方法。該方法可以正則規(guī)則和字符串想關(guān)聯(lián)。并返回匹配器對象。
3),使用Matcher對象中的方法即可對字符串進(jìn)行各種正則操作。
以上是“javaSE知識點(diǎn)有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。