第一篇:黑馬程序員java培訓(xùn)就業(yè)班筆記:day14(多線程、String類)總結(jié)
Day14總結(jié):
1、wait和sleep的區(qū)別:(面試題)
1、sleep指定時間,wait可以指定時間,也可以不用指定時間。
2、wait方法必須定義在同步中,sleep方法不一定。
3、在同步中wait sleep對于執(zhí)行權(quán)和鎖的處理不同: i.Sleep釋放CPU執(zhí)行權(quán),但是沒有釋放鎖。ii.Wait釋放執(zhí)行權(quán)、釋放鎖。實現(xiàn)代碼: Public void run(){ Synchronized(this){ Code…sleep(10);//此線程進入凍結(jié)狀態(tài),釋放了執(zhí)行權(quán),并沒有釋放鎖。
Wait();//等待狀態(tài)下,釋放執(zhí)行權(quán)、釋放鎖,因為它需要被對象喚醒,所以要釋放鎖
} } Public void method(){ Synchronized(this){
notifyAll();//喚醒上面所有的線程。但是此時t0、t1并沒有執(zhí)行,因為鎖還在此線程中,只有當(dāng)它執(zhí)行完畢之后,釋放鎖。它們獲取鎖之后才有機會執(zhí)行。
} }
2、停止線程:
1、Stop方法已經(jīng)過時,為什么?因為該方法具有不固定的安全性。
如何停止線程? 只有一種方法:
線程執(zhí)行的代碼結(jié)束,線程會自動終止。
1、run方法中通常有循環(huán),所以只要循環(huán)結(jié)束即可。所以只要控制循環(huán)條件。最簡單的方式就是定義標(biāo)記。
2、如果run中有同步可以讓線程出現(xiàn)凍結(jié)狀態(tài)的方法,比如wait那么線程就不會去讀取標(biāo)記。這時必須讓線程恢復(fù)到運行狀態(tài)才可以有機會讀取到標(biāo)記,所以通過正常的恢復(fù)方法比如notify、sleep時間到,但是如果沒有辦法正?;謴?fù),就必須使用強制手段,interrupt方法,強制將線程的凍結(jié)狀態(tài)清除,讓線程恢復(fù)運行。其實就是讓線程重新獲取讀取標(biāo)記、結(jié)束。但是別忘了強制動作會產(chǎn)生異常要處理。實現(xiàn)代碼:
StopThreadDemo.java
class StopThread implements Runnable
{ private boolean flag=true;//定義標(biāo)記控制住循環(huán)。public synchronized void run(){ while(flag)//開始true、此時定義標(biāo)記控制循環(huán)。
{
try
{
wait();//當(dāng)存在同步時,wait方法不會讓線程去讀取標(biāo)記。此時主線程結(jié)束了,但是這兩個線程卻在這里等待了。并沒有結(jié)束。
}
catch(InterruptedException e)
{
System.out.println(Thread.currentThread().getName()+“....Exception”);
setFlag();//如果發(fā)生了強制中斷,只要把狀態(tài)切斷到假。
}
System.out.println(Thread.currentThread().getName()+“...”);} } public void setFlag(){ flag=false;} }
class StopThreadDemo { public static void main(String[] args){ StopThread st=new StopThread();Thread t1=new Thread(st);Thread t2=new Thread(st);t1.start();t2.setDaemon(true);//標(biāo)記成了守護線程。
t2.start();
for(int x=0;;x++){
if(x==50)
{
st.setFlag();
t1.interrupt();//t1將它的凍結(jié)狀態(tài)強制結(jié)束。
t2.interrupt();//中斷方法。其實不是中斷線程。而且還拋出了異常。
//其實會將凍結(jié)中的線程強行恢復(fù)到運行狀態(tài),就會讀到標(biāo)記。這就是中斷線程。并不是結(jié)束線程。一定要注意要區(qū)分。
//
break;
}
System.out.println(Thread.currentThread().getName()+“....”);}
System.out.println(“Hello World!”);} }
3、守護線程:setDaemon();線程標(biāo)記,守護線程,當(dāng)正在運行的線程是守護線程時,JVM自動退出,該方法在開啟之前調(diào)用,也就是說在start方法之前調(diào)用。
線程分兩種:
前臺線程:自己創(chuàng)建的線程都是前臺線程。
后臺線程:一旦調(diào)用了此方法為守護線程之后的線程都是守護線程。
區(qū)別:都是線程,啟動后都再搶奪CPU的執(zhí)行權(quán),這里是沒有區(qū)別的,最大的區(qū)別就是如果線程結(jié)束了,正在運行的后臺線程也隨著結(jié)束,簡單的說后臺線程是以來前臺線程而執(zhí)行的。
4、線程細(xì)節(jié):
1、join:當(dāng)A線程執(zhí)行到B線程時,那么A線程就會等待,等B執(zhí)行完畢,A才會執(zhí)行。
代碼實現(xiàn):
D1.join();d1加入,說明了主線程必須先釋放執(zhí)行權(quán)給它,等到d1結(jié)束之后主線程才恢復(fù)執(zhí)行狀態(tài),所以輸出結(jié)果是等d1全部都執(zhí)行完畢之后,才有其他線程的交替執(zhí)行。
記住:誰把執(zhí)行權(quán)給了誰,就只和給的對象的執(zhí)行權(quán)有關(guān),等它結(jié)束之后,就會重新獲取執(zhí)行
記?。褐骶€程是因為誰放棄了執(zhí)行權(quán),就只和那個線程有關(guān)系權(quán),與其他線程無關(guān)。
2、優(yōu)先級:代表搶奪資源的頻率。有兩種方法:getPriority setPriority來獲取優(yōu)先級和設(shè)置優(yōu)先級,只有十個數(shù)字可以使用1-10這十個數(shù)字,同時線程中提供了幾個特殊的方法: 線程類中提供了MAX_PRIORITY MIN_PRIORTY NORM_PRIORTY。
3、yield:結(jié)束該線程,釋放執(zhí)行權(quán)。
4、toString();獲取線程詳細(xì)信息,包括線程組、線程名、所屬線程。實現(xiàn)代碼:ThreadMethodDemo.java
5、string類:
1、字符串的特點:
1、java中用String類來描述字符串。
2、字符串是一個特殊的對象,一旦初始化就不可以被改變,因為是常量。面試題1: String s=“abc”;String s1=new Strng(“abc”);是否相同?
前者“abc”是一個對象。后者是兩個對象,new string()代表一個對象,“abc”也代表一個對象。
Sop(s1==s2);==比較的是數(shù)據(jù)。false Sop(s1.equals(s2));比較的是內(nèi)存的地址值,equals覆寫了Object類中的equals方法。True
面試題2: String a=“abcd”;//在緩沖池創(chuàng)建了一個abcd的字符串。String a1=“ab”;//a1和a2都是變量,無法確定。
String a2=“cd”;String b=a1+a2;//b是要重新進行分配的。
String c=“ab”+“cd”;//兩個都是常量值,用連接符連接在一起還是字符創(chuàng)。abcd System.out.println(“a==b:”+(a==b));//false System.out.println(“a==c:”+(a==c));//true
2、常見操作方法:
1、獲?。?/p>
a)獲取長度:
Int length();數(shù)組長度是個屬性,字符串是個方法 b)獲取字符串中的字符:
charAt(int index);返回值是一個字符。
c)一個字符或者一個字符串在一個字符串中的位置
Int indexof(int ch)Int indexof(int ch,int fromIndex)Int indexof(ch,fromIndex)Int indexof(srting,fromindex)Int lastIndexof(ch);注意:這些獲取索引位的方法,如果沒有查找的內(nèi)容,返回-1,所以這個方法。
d)獲取部分字符串:
String substring(begin,end)
2、判斷:
a)是否包含指定的字符串
Boolean contains(String)
b)是否是以指定的字符串開頭
Boolean startsWith(String)c)是否是以指定的字符串結(jié)尾
Boolean endwith(String)d)忽略大小寫判斷字符串
Boolean equalsIgnoreCase(string)
3、轉(zhuǎn)換:
a)將字符串轉(zhuǎn)成大小寫
String toLowerCase();String toUpperCase();b)將字符串轉(zhuǎn)成數(shù)組
Byte[] getBytes();Char[] getChar();c)將字符串轉(zhuǎn)成字符串?dāng)?shù)組
String[] d)將字符串中的內(nèi)容進行替換
String replace(oldch1,new ch2)String replace(string1,string2)e)去除字符串兩端的空白
Trim();如何查閱API文檔的小技巧,先查找返回值類型,縮小查找范圍。實現(xiàn)代碼:
ublic static void main(String[] args){
// stringMethod4();
String str = “
ab c
”;
System.out.println(“-”+str.trim()+“-”);
String s = String.valueOf(4);
System.out.println(4+“");
System.out.println(”ab“+”cd“);
System.out.println(”ab“.concat(”cd“));
}
private static void stringMethod4(){
String str = ”lisi.wangwu.zhaoliu“;
} String[] strs = str.split(”.“);for(int i = 0;i < strs.length;i++){ System.out.println(strs[i]);}
str = ”hello“;
String s = str.replace('a', 'k');
System.out.println(”s=“+s);System.out.println(str);private static void stringMethod3(){
String str = ”aBCd“;
String s = str.toLowerCase();System.out.println(s);String s1 = str.toUpperCase();System.out.println(s1);
System.out.println(str);
char[] arr = str.toCharArray();
for(int x = 0;x System.out.println(arr[x]);} } private static void stringMethod2(){ String str = ”ThreadDemo.java“; System.out.println(”contains(Demo):“+str.contains(”Demo“));System.out.println(”starsWith(Thread):“+str.startsWith(”Thread“));System.out.println(”endsWith(.java):“+str.endsWith(”.java“));System.out.println(”isEmpty:“+str.isEmpty());str = ”abc“;說 System.out.println(str.equalsIgnoreCase(”abC“));} private static void stringMethod(){ String str = ”abcdaef“;System.out.println(”length;“+str.length()); System.out.println(”charAt(2):“+str.charAt(2)); System.out.println(”indexOf(a):“+str.indexOf('a',2)); System.out.println(”lastIndexOf(a):“+str.lastIndexOf('k')); System.out.println(”substring(1,3):"+str.substring(0,str.length()));} Day05 上午: 1、數(shù)組的靜態(tài)初始化 多種定義格式: Int[] arr=new int[]//標(biāo)準(zhǔn)格式,可以明確數(shù)組的數(shù)據(jù)類型,和數(shù)組名,但是不知道數(shù)組的長度 Int arr[]=new int[] Int[] arr=new int[]{2,1,3,4,5,}//通過大括號可以標(biāo)示出數(shù)組中的內(nèi)容,此處最好別寫長度,因為容易出錯,因為即初始化實體,又初始化實體中的元素。 Int[] arr={2,1,3,4,5};//可以明確數(shù)組的數(shù)據(jù)類型,和數(shù)組名,也可以知道數(shù)組中的內(nèi)容。 2、arr.length:方便獲取數(shù)組中的元素個數(shù)的方式。 3、操作數(shù)組的最基礎(chǔ)的思想以及核心思想: a)最基礎(chǔ)的思想:就是遍歷。什么是遍歷。 Eg:int[] arr = new int[3];int[] arr = {4,8,9,2,6,9};//明確了數(shù)組的類型和長度,并明確了數(shù)組中元素的內(nèi)容。 // int[] arr1 = new int[]{4,8,9};//方便獲取數(shù)組中的元素個數(shù)的方式,可以使用數(shù)組實體一個屬性。length System.out.println(“l(fā)en:”+arr.length); for(int x=0;x if(x%2==1) System.out.println(“arr[”+x+“]=”+arr[x]);//arr[0] = 4;} 這就是遍歷的思想,獲取數(shù)組中的元素,通常會用到遍歷。 b)核心思想:就是操作數(shù)組中元素的角標(biāo),角標(biāo)即索引,因為存數(shù)據(jù)的最終目的就是取出數(shù)據(jù)使用,就是操作角標(biāo),操作動作: 1、給數(shù)組角標(biāo)上的元素賦值,2、獲取角標(biāo)上元素的值,存儲都得用角標(biāo) 4、數(shù)組中常見的操作: a)獲取最值: 思路: 1、首先我們要定義一個功能完成獲取數(shù)組中最大值的動作; 2、定義個函數(shù)來實現(xiàn)這一功能;明確結(jié)果,整數(shù)數(shù)組中的最大值,int,明確是否有未知內(nèi)容參與運算,參數(shù)列表中有一個參數(shù),數(shù)組類型int[],一定要注意這里是數(shù)組類型,不是int型; 3、如何實現(xiàn)功能細(xì)節(jié)呢? 1、對數(shù)組中的元素進行比較,將比較后比較大的值進行記錄,并參與下一次比較,當(dāng)數(shù)組中的元素都比較完成后,最大值就已經(jīng)被記錄下來了。 2、每次比較的較大的值不確定,定義一個變量進行記錄,該變量如何初始化呢?只要初始化為數(shù)組中的人一個元素即可。 3、應(yīng)該讓數(shù)組中的元素自動和該變量記錄的元素進行比較,所以可以使用遍 歷,獲取數(shù)組中的每一個元素。 4、當(dāng)遍歷到元素比較變量中的記錄的元素大,用該變量記錄住更大的元素。 5、遍歷結(jié)束后,變量存儲就是數(shù)組中的最大值。實現(xiàn)代碼:eg: Public static int getMax(int arr){ /.定變量記錄較大的值; Int max=arr[0];//初始化數(shù)組中的任意個元素; //對數(shù)組進行遍歷比較 For(int x=1;x Max=arr[x];} Return max;} 同樣有另外一種方式獲取最大值 Public static int getMax(int[] arr){ Int maxIndex=0;//初始化為數(shù)組中一個元素的角標(biāo) For(int x=1;x maxIndex=x;} Return arr[maxIndex];} b)排序: 1、選擇排序: 首先通過數(shù)組中元素的比較方式來分析: 用數(shù)組中第一個角標(biāo)的元素與數(shù)組中第二個角標(biāo)的元素進行比較,發(fā)現(xiàn)9比6大,進行位置置換,此處應(yīng)該定義一個三方變量,用來記錄住置換過程的元素值,然后再用第一個角標(biāo)的元素與下一個角標(biāo)元素進行比較,按照全面的原則進行置換位置,如果前者小于后者,則不置換位置,一次比較,當(dāng)?shù)谝惠喗Y(jié)束之后第一個角標(biāo)出能取的該數(shù)組中最小的元素的值,然后再用第一個角標(biāo)的元素開始和下一個角標(biāo)的元素進行比較,同理,當(dāng)?shù)诙喗Y(jié)束后,第二個角標(biāo)處獲取了該數(shù)組中的第二小的值。所以我們發(fā)現(xiàn)當(dāng)依次這樣比較下去,就可以對數(shù)組中的元素進行排序,當(dāng)比較到arr.length-1元素時,發(fā)現(xiàn)只剩下這一個元素,沒有其他元素和它進行比較了。思路: 1、首先定義一個功能函數(shù)對數(shù)組進行排序,2、明確結(jié)果,沒有返回值,因為它只是對數(shù)組進行排序的一個動作,明確是否有未知內(nèi)容參與運算,有,數(shù)組類型int[] arr 實現(xiàn)代碼: Public static void selectSort(int[] arr){ For(int x=0;x if(arr[x]>arr[y]){ Int temp=arr[x];Arr[x]=arr[y];Arr[y]=temp;} } } } 優(yōu)化后的選擇排序: 從上面的排序圖中我們可以知道,對數(shù)組中元素進行置換位置的次數(shù)過多,也就是對堆內(nèi)存的操作頻繁,降低了性能,下面我們可以通過這種方式對性能優(yōu)化。 思路: 在棧內(nèi)存中我們定義兩個變量,分別用來記錄較小的元素的值和較小元素的角標(biāo),然后對其進行初始化,至于初始化的值只要是數(shù)組中的任意元素即可,然后拿數(shù)組中的元素與它進行比較,如果發(fā)現(xiàn)拿去比較的元素比變量中記錄的數(shù)值要小,那么就進行位置置換,并記錄下較小的元素的角標(biāo),依次把數(shù)組中的元素遍歷完,就可以獲取數(shù)組中的最小元素的值和角標(biāo),然后我們拿初始化的值和獲取的最小的元素進行位置的置換,這樣以來當(dāng)我們獲取了數(shù)組中的元素的最小的時候,堆內(nèi)存中的只用操作一次位置即可,這樣的就提高性能。實現(xiàn)代碼: Public static void selectSort_2(int[] arr){ For(int x=0;x Num=arr[y];Index=y;} If(index!=x){ int temp = arr[x];arr[x] = arr[index];arr[index] = temp; } } } 注意:復(fù)習(xí)的時候添加注釋 2、冒泡排序: 首先通過排序方式來分析其步驟: 通過排序方式,可以知道是用數(shù)組中的元素挨個比較,如果前面的元素的值比它下一個角標(biāo)的元素大,則進行位置置換,然后再用第二個角標(biāo)的元素與下一個角標(biāo)的元素進行比較,同樣如果下一個角標(biāo)的元素比它小,則進行位置置換,這樣當(dāng)比較到arr.length-1個元素時已經(jīng)沒有 和它進行的比較的元素了,當(dāng)?shù)谝惠啽容^結(jié)束后,我們可以知道最后一個角標(biāo)的元素為該數(shù)組中的最大值,按照同樣的原理進行下一次比較,依次獲取了比較大的元素的值。 實現(xiàn)代碼: Public static void bubbleSort(int[] arr){ For(int x=0;x If(arr[y]>arr[y+1]){ //位置置換 } } } } c)折半查找: 首先分析數(shù)組元素的查找方式: 首先要明確數(shù)組時有序的。 首先定義三個變量min、mid、max分來用來記錄最小角標(biāo)、中間角標(biāo)、最大角標(biāo),中間角標(biāo)的獲取為(min+max)/2;獲取中間角標(biāo)之后,就可以獲取中間角標(biāo)對應(yīng)的元素arr[mid];用我們所需要查找的key與中間角標(biāo)運算進行比較,如果key>arr[mid];那么此時min的位置就是mid的下一個角標(biāo),min=mid+1;然后再次獲取中間角標(biāo)的元素,mid=(min+max)/2,同時也獲取了中間角標(biāo)對應(yīng)的數(shù)組元素,arr[mid],然后同理,拿key與中間角標(biāo)的元素進行比較.同樣的原則,依次比較,直到key==arr[mid]的時候獲取key.如果當(dāng)出現(xiàn)了min>max或者時候則說明我們要查找的key在該數(shù)組中布存在,return-1; 實現(xiàn)代碼: Public static void binarySearch(int[] arr int key){ Int min,mid,max;Min=0;Max=arr.length-1;Mid=(min+max)>>1//相當(dāng)于/2,右移的效率比它要高 While(arr[mid]!=key){ If(key>arr[mid])Min=mid+1;Else if(key Min=mid-1;If(max Return mid;} 注意:復(fù)習(xí)的添加代碼注釋 總結(jié):折半查找也稱二分查找,這種查找可以提高效率,但是被查找的數(shù)組的額元素必須是有序的。不能對無序的數(shù)組進行排序后再用折半查找,因為這時候數(shù)組中元素的角標(biāo)已經(jīng)發(fā)生變化了。 5、查表法思想: a)什么時候使用查表法? 當(dāng)元素很多,而且這些元素與數(shù)組有對應(yīng)關(guān)系,而且這些數(shù)字都有角標(biāo)的規(guī)律的時候。 擴展:什么時候使用數(shù)組? 當(dāng)同一類型的元素較多時,就使用數(shù)組這個容器對數(shù)據(jù)進行存儲。b)查表法思想的代碼體現(xiàn): 0 1 2 3 4 5 6 7 10 11 12 13 14 15 '0', '1', '2', '3', '4','5', '6',' 7', '8', '9','A',' B', 'C' ,'D', 'E' ,'F' 我們發(fā)現(xiàn)十六進制中一共有16個元素,而且每通過&15獲取的數(shù)字都再15之內(nèi),都有對應(yīng)的十六進制元素,而且元素對應(yīng)的數(shù)字正好有規(guī)律,而且符合了數(shù)組這種容器的特點角標(biāo),那么可以將十六進制的元素都存儲到數(shù)組中,將每次&15的結(jié)果作為角標(biāo)去查這個數(shù)組,就可以獲取到十六進制的對應(yīng)的元素。這就是查表思想。 代碼體現(xiàn): Public static void searchList(int num){ //定義一個十六進制的元素表 Char[] arr={'0', '1', '2', '3', '4','5', '6',' 7', '8', '9','A',' B', 'C' ,'D', 'E' ,'F'};//定義一個char類型元素的數(shù)組,用于存儲每次獲取到的十六進制值。Char[] chs=new char[8];Int pos=chs.length;While(num!=0){ Int temp=num&15;Chs[--pos]=arr[temp];Num=num>>>4;} For(int x=pos;x 通過上面我們可以知道那么是否可以定義這樣的一個功能函數(shù)呢?用來對十進制、二進制、八進制、十六進制進行轉(zhuǎn)換? 思路: 1、明確結(jié)果,沒有返回值,只是對給定的數(shù)據(jù)轉(zhuǎn)換的功能。 2、明確是否有未知內(nèi)容參與運算,有,是什么?求的數(shù)值num,十六進制是&15,八進制是&7,二進制是&1,那么&的這個是不確定的,我們定義為變量 base,當(dāng)這個數(shù)值通過&上這些數(shù)據(jù)后,要取出后面的數(shù)值,我們通過右移來實現(xiàn),但是各個進制的不一樣右移的位置數(shù)也是不一樣的,十六進制是無條件右移四位,八進制是無條件右移三位,二進制是無條件右移1位,所以這個數(shù)也是不確定的,定義變量 offset 實現(xiàn)代碼: //十進制--二進制 public static void toBin(int num){ trans(num,1,1);} //十進制--八進制 public static void toOctal(int num){ trans(num,7,3);} //十進制--十六進制 public static void toHex(int num){ trans(num,15,4);} Public static void trans(int num,int base,int offset){ If(num==0){ Sop(0);;Return;} //定義一個十六進制的元素表 Char[] arr={0', '1', '2', '3', '4', '5', '6', ' 7', '8', '9', 'A',' B', 'C' ,' D', 'E' ,'F'};Char[] chs=new char[32];Int pos=chs.length;While(num!=0){ Int temp=num&base;Chs[--pos]=arr[temp];Num=num>>>offset;} For(ingt x=pos;x System.outr.println(chs[x]);} } 注意:復(fù)習(xí)的添加代碼注釋。 這一章節(jié)自己還不是很熟悉,能理解,但是不能獨立寫出代碼,在以后的幾天內(nèi)要每天都要一遍,并自己獨立寫出代碼,做到思想理解透徹。先要產(chǎn)生一天的宏觀思想。復(fù)習(xí)方法: 首先總結(jié)當(dāng)天學(xué)習(xí)的方法。遇到不會的先放到一邊。每天晚上睡著覺之前要回憶一遍。 Day06總結(jié): 上午 1、二維數(shù)組 格式: Int[][] arr=new int[2][3];[2]代表1維數(shù)組的個數(shù); [3]代表1維數(shù)組有三個元素; 內(nèi)存圖: 分析: 通過對內(nèi)存圖分布可知,首先在棧內(nèi)存中加載main函數(shù),開辟空間,定義一個變量arr,在堆內(nèi)存中通過New創(chuàng)建一個數(shù)組實體int[2],并分配其地址值為0x0045,數(shù)組元素值進行默認(rèn)初始化為Null;然后把地址值賦值給棧內(nèi)存中的arr.在堆內(nèi)存中開辟兩塊空間,分別用來存放二維數(shù)組中的數(shù)組元素,分配其地址值分別為0x0056、0x0089,然后對將地址值傳給二維數(shù)組中的元素,所以說對內(nèi)存中二維數(shù)組存儲的是一維數(shù)組的地址值。最后變量通過二維數(shù)組的地址0x0045指向二維數(shù)組。 注意:二維數(shù)組中必須指定長度、以及實體沒有對二維數(shù)組進行初始化時默認(rèn)為null; 2、對二維數(shù)組的遍歷(大圈套小圈思想)For(int x=0;x 3、面向?qū)ο蟮睦斫猓?/p> 特點: 1、面向?qū)ο缶褪歉先藗兯伎剂?xí)慣的一種思想。 2、從面向過程的執(zhí)行者,轉(zhuǎn)變成了面向?qū)ο蟮闹笓]者 3、面向?qū)ο髮?fù)雜的事情簡單化了。 其實面向?qū)ο笫且环N思想,是面向過程而言,將復(fù)雜的事情變的更簡單了。通過把大象放到冰箱里這個列子來理解面向?qū)ο蟮母拍?/p> 面向過程:把冰箱門打開、存儲大象、關(guān)閉冰箱;強調(diào)的過程注重行為; 面向?qū)ο螅罕?打開、冰箱.存儲、冰箱.關(guān)閉;強調(diào)的是冰箱這個對象。 面試題:你怎么理解面向?qū)ο螅?/p> 首先說面向?qū)ο蟮奶攸c:它是一種思想,它讓復(fù)雜的問題簡單化,它把執(zhí)行者變成了指揮者。 然后舉例子來說明,最牛的就是結(jié)合實際場景來說:其實面試官你就是在用面向?qū)ο蟮乃枷朐谒伎紗栴},為什么這么說?因為公司業(yè)務(wù)蒸蒸日上,需要招更多的人來完成項目,所以才在這里招聘人員,你需要找一些具備專業(yè)編程經(jīng)驗的人,來幫公司完成工作,那么我就是那個對象,因為我具備專業(yè)編程能力,你就是那個指揮者,指揮我來做事,至于我怎么去完成編程任務(wù),你是不需要去知道,你只要結(jié)果了就可以了,這其實就是把你之前的工作簡化了,你不必再事必躬親了。這就是面向?qū)ο笏枷氲捏w現(xiàn)。 同時可以結(jié)合去飯店吃飯,在家做事等等列子來說明面向?qū)ο蟮乃枷搿?/p> 擴展:OOP:面向?qū)ο缶幊獭?/p> OOA面向?qū)ο蠓治觥?/p> OOD:面向設(shè)計。還有面向接口、面向框架、面向?qū)ο蟮恼Z言:C++、JAVA、C# 4、在實現(xiàn)功能,先找java當(dāng)中是不是提供好了相關(guān)的對象,沒有對象自己造一個對象。比如說公司招聘人員找不到人的時,這時公司就需要自己在公司內(nèi)部培養(yǎng)人,也就是自己造對象。 5、類和對象關(guān)系: a)類到底是什么? 類就是對現(xiàn)實生活中事物的描述,描述中包含了該類事物的共性內(nèi)容。Class Car(){ Int num;String color;Void run(){} } 在類中定義的變量和函數(shù)都稱為類中的成員。成員: 成員變量---屬性 成員函數(shù)---行為 b)什么是對象? 對象就是該類事物實實在在存在的個體。 Eg:現(xiàn)實生活中的對象:張 三、李四 想要描述:提取對象中的共性內(nèi)容,對具體的抽象。 描述時:這些對象的共性有姓名年齡性別學(xué)習(xí)java的功能。對象也可以理解為其實就是個容器,用來存儲更多的數(shù)據(jù),存儲的都是每一個對象特有的數(shù)據(jù),而類就是這些數(shù)據(jù)所屬的屬性。 用java語言來描述一個小汽車 描述事物:無非就是描述事物的屬性和行為 屬性:輪胎數(shù)、顏色 行為:運行 Eg: Class Car { String color=“red”;Int num=4;Run(){ System.out.println(color+“"+num);} } Class CarDemo { Public static void main(String[] args){ Car c=new Car();C.color=”bule“;C.num=5;C.run();m Car c1=new Car();C1.num=8;C1.color=”green“;C1.run();} } 重點:分析上述代碼在內(nèi)存中的分布: 復(fù)習(xí)的時候?qū)憙?nèi)存分析: 6、成員變量和局部變量的區(qū)別: 1、源代碼中定義位置不同: 成員變量:定義在類中,在整個類中有效。局部變量:定義在函數(shù)中,在局部范圍內(nèi)有效。簡單一句話:作用范圍不一樣,成員變量作用于整個類中,局部變量作用于函數(shù)中,或者語句中。 2、在內(nèi)存中的位置和事件不同: 生命周期不同: 成員變量:隨著對象的創(chuàng)建的而出現(xiàn)在堆內(nèi)存中,隨著對象被回收而消失。 局部變量:隨著變量所屬局部區(qū)域的運行,而出現(xiàn)在棧內(nèi)存中,隨著所屬區(qū)域運行結(jié)束而釋放。 3、變量使用的初始化: 成員變量:因為堆內(nèi)存中都有默認(rèn)初始化值,對于引用型變量默認(rèn)值就是null;局部變量:因為在棧內(nèi)存中都沒有默認(rèn)初始化值,必須手動初始化后才可以參與運算。 7、匿名對象: 即沒有名字的對象,簡化書寫用的。基本使用: 1、當(dāng)對對象的方法只調(diào)用一次時,可以用匿名對象來完成 這樣寫比較簡化,如果對一個對象進行這個成員的調(diào)用,必須給這個對象起個名字 2、可以將匿名對象作為實際參數(shù)進行傳遞。一旦對對對進行多個成員操作時。必須要對對象起個名字。 Eg: Main(){ Show(new Car())} Public static void show(Car c) { C.num=3; C.color=”back";C.run();} 8、面向?qū)ο笕齻€特征: 封裝: 是指隱藏對象的屬性和實現(xiàn)細(xì)節(jié),僅對外提供公共訪問方式,凡是面向?qū)ο蟊仨氂蟹庋b性。 特點: 將變化隔離 便于使用 提高復(fù)用性 提高安全性 原則: 1、將不需要對外提供的內(nèi)容都隱藏起來。 2、把屬性都隱藏,提供公共方法對其訪問。在代碼中的體現(xiàn): 1、將成員變量都私有化,并通過共有的方法對其進行訪問,這兩個方法是:setXxxgetXxx 2、只要不準(zhǔn)備對外提供的全部都封裝起來,3、私有僅僅是封裝的一種表現(xiàn)形式,函數(shù)是最小的封裝體。方法需要私有嗎? Public static void selectSort(){ Swap();} Private void swap()//此處私有是因為位置置換不用提供給用戶。{ } 代碼實現(xiàn): Class Person { Private int age;//為了不讓其他程序直接訪問age屬性,避免錯誤的數(shù)據(jù),可以使用一個關(guān)鍵字來完成private私有,它是一個權(quán)限修飾符。 Public void setAge()//對外提供函數(shù)是可以控制你輸入的參數(shù)。//一個成員變量通常對應(yīng)的兩個方法、{ If(a>130||a<0){ Age=a; Speak();} Else System.out.println();} Public void getAge(){ Return age;} Void speak(){ Sop();} } Class PersonDemo { Public static void main(String[] args){ Person p=new Person();P.age=-20;//錯誤數(shù)據(jù)是因為對象直接訪問age屬性造成的。P.speak();} } 總結(jié):之所以對外提供訪問方式,就是因為可以在訪問方式中加入邏輯判斷等語句 對訪問的數(shù)據(jù)進行操作,提高代碼的健壯性。凡是set開頭的返回值類型是void,get開頭的跟它的返回值類型一致。 Day10總結(jié): 1、多態(tài)的特點: 1、成員變量: 當(dāng)在子父類中出現(xiàn)了相同的非私有成員變量時,在多態(tài)調(diào)用中的特點: 在編譯時:參考引用型變量所屬類中是否有調(diào)用的成員變量,如果有編譯通過,如果沒有編譯失敗。 在運行時:參考引用型變量所屬的類中的成員。 簡單一句話:對于成員變量無論是編譯還是運行都參考引用型變量所屬類中的成員變量。 也就是說:成員變量看等號左邊。 2、成員函數(shù): 當(dāng)子父類中出現(xiàn)一模一樣的函數(shù)時,在多態(tài)調(diào)用中的特點: 在編譯時:參考引用型變量的所屬的類中是否有調(diào)用的成員函數(shù)。在運行時:參考的是對象所屬的類中是否有調(diào)用的成員函數(shù)。 原因是:編譯時期應(yīng)該參考父類,運行時期應(yīng)該參考子類。因為成員函數(shù)上有一個特點覆蓋。 簡單一句話:對于成員函數(shù),編譯看左邊,運行看右邊。 3、靜態(tài)函數(shù): 在編譯時期:參考引用型變量所屬的類中是否調(diào)用的靜態(tài)函數(shù),如果有編譯通過,如果沒有編譯失敗。 在運行時期:參考的還是引用型變量所屬的類中的靜態(tài)函數(shù)。簡單一句話:對于靜態(tài)函數(shù),無論是編譯還是運行都看左邊 總結(jié):對于多態(tài)成員而言,無論編譯還是運行都看左邊,只有成員非靜態(tài)函數(shù),編譯看左邊,運行看右邊,因為覆蓋的特性。 2、多態(tài)的應(yīng)用: 代碼實現(xiàn): Object:所有類的父類,該類中的方法所有對象都具備。代碼實現(xiàn): Class Demo extends Object { Private int num;Demo(int num){ This.num=num;} 通常都會按照對象自身的特點對對象進行比較,比如:現(xiàn)在要比較兩個Demo對象中null值是否相同。} Public boolean compare(Demo b){ Return this.num=d.num; } 發(fā)現(xiàn)Demo繼承Oject已經(jīng)具備了比較對象的方法,所以沒有必要再定義新的方法compare了,直接使用equals就可以了,可是Object equals比較的是地址值,不是我們所需的,那就保留的父類的功能聲明,建立自身的比較內(nèi)容,這就是覆蓋。Public boolean equals(Object obj){ If(!(Object instanceof Deno))Return false;Demo d=(Demo)obj;向下轉(zhuǎn)型。 Return this.num=d.num;此處體現(xiàn)了多態(tài)的特性。} Public String toString(){ Return “demo:”+num;} Class ObjectDemo { Public static void main(String[] args){ Demo d1=new Demo(4);Demo d2=new Demo(4);Sop(d1.toString());Sop(d1);Sop(c1.getName());Sop(d1.compare(d2));} } 4、內(nèi)部類: 將一個類定義在另外一個類的里面的類稱為內(nèi)部類 當(dāng)一個類要直接訪問另外一個類的成員時,可以將這個類定義到另一個類里面,稱為另一個類的內(nèi)部類。 內(nèi)部類訪問的規(guī)則: 1、內(nèi)部類可以直接訪問外部類中的成員。 2、外部類需要創(chuàng)建內(nèi)部類對象才可以訪問內(nèi)部類中的成員。 在描述事物時,事物中還有具體的事物時,而且這個內(nèi)部事物在訪問著外部的事物時。這時對這個內(nèi)部事物的描述,就可以用內(nèi)部類完成。 內(nèi)部類出于外部類的成員位置上是可以被成員修飾符所修飾的。Public Private:將內(nèi)部類私有化時,只能對外提供方法,對內(nèi)部類的控制。 Static:當(dāng)內(nèi)部類中定義了靜態(tài)的成員時,該內(nèi)部類必須靜態(tài)的,否則編譯失敗。代碼體現(xiàn): Class Outer { Static int num=4;Static class Inner //內(nèi)部類,為什么要定義內(nèi)部類? 當(dāng)一個類要直接訪問另一個類中的成員時??梢詫⑦@個類定義到另一類里面。{ Static void show(){ Sop(“show run”+num);} Public void method(){ Inner in=new Inner();In.,show();} } } Class InnerClassDemo { Public static void main(String[] args){ //Outer out=new Outer(); //out.method(); //System.out.println(“Hello World!”); //當(dāng)訪問一個外部類的內(nèi)部類時,先由外部類對象再有內(nèi)部類對象。 //Outer.Inner in=new Outer().new Inner();//要指明內(nèi)部類所處的外部類 //in.show(); //內(nèi)部類靜態(tài)化,要調(diào)用的非靜態(tài)的方法show(); //Outer.Inner in=new Outer.Inner(); //in.show(); //如果show方法也是靜態(tài)的,要調(diào)用靜態(tài)的方法show(); Outer.Inner.show();} } 5、匿名內(nèi)部類:沒名字的內(nèi)部類。 就是內(nèi)部類的簡化寫法。 前提:內(nèi)部類可以繼承或者實現(xiàn)一個外部類。代碼實現(xiàn): 格式: New 父類名or 接口名(){子類的具體內(nèi)容} Abstract class AbdsDemo { Abstract void show1();Abstract void show2();} Class Outer { Int num=4;New AbsDemo(){ Void show()//匿名內(nèi)部類 { Sop(“num===”+num);} }.show();} Public void method2(){ AbsDemo a=new AbsDemo();{ Public void show1();Public void show2();};A.show1();A.show2();//要想調(diào)用兩個方法,怎么做?起個名稱即可 當(dāng)里面有多個方法的時候建議不要寫匿名內(nèi)部類。 } -----------------------------interface Inter { void show();} class Outer { //補足代碼。最好用匿名內(nèi)部類 static Inter method()//為什么是Inter類型 { return new Inter() { public void show() { System.out.println(“show run”); } }; } } class InnerClassTest { public static void main(String[] args) { Outer.method().show(); /* Outer.method():Outer類中有一個method方法,而且這個方法是靜態(tài)的。 Outer.method().show 會返回一個對象,而且這個對象還可以調(diào)用show方法 說明這個對象肯定是Inter類型。 */ } } ------------------------------ 6、異常: 是在運行時期發(fā)生的不正常情況 Java發(fā)現(xiàn)不正常的情況都包含著一些常見信息,并 將這些信息進行了對象的封裝。異常這種機制,其實就是java按照面向?qū)ο蟮乃枷雽⒊霈F(xiàn)的問題封裝成了對象。在進行問題分析時,發(fā)現(xiàn)問題有很多種,但是不斷向上抽取,最終問題可以歸納為兩種,一種是可以針對處理的一種是通常不進行處理的。 在java中的體現(xiàn)一個是Exception ,一個是Error,后者一般針對處理。 無論是異常還是錯誤,他們都有名稱信息等共性的內(nèi)容。 可以繼續(xù)抽取形成一個父類:throwable可拋出。Throwable |---Error |---Exception 異常和錯誤都有一個特點:其子類的名稱的后綴名都是父類名。 該體系具備一個特殊的特性叫做可拋性,該體系中的類可以被關(guān)鍵字throws拋出。 該體系中的類產(chǎn)生的對象可以被Throw拋出,簡單說該體系可以被Throws 和throw操作。 Throw 和throws的區(qū)別: Throws:定義在函數(shù)上,用于聲明函數(shù)的可能出現(xiàn)的問題,后面跟異常類,可以跟多個,用逗號隔開、Throw:定義在函數(shù)內(nèi),用于拋出異常對象因為程序的跳轉(zhuǎn),后面跟的是異常對象。 If判斷和異常處理的區(qū)別: If判斷是將正常代碼和異常代碼寫在一起。閱讀性極差,異常處理將問題代碼和異常處理代碼分離。代碼實現(xiàn): Class Demo { 功能的定義著在定義工呢過時,發(fā)現(xiàn)該功能容易因為未知內(nèi)容的不確定性的出現(xiàn)的問題。為了讓調(diào)用者明確,有可能有問題,需要在函數(shù)上對問題進行聲明。 需要一關(guān)鍵字throw異常名。 Int div(int a,int b)throws Exception//拋出異常是為聲明異常問題,讓調(diào)用者去處理。{ If(b==0)Throw new ArithmeticException(“除數(shù)為零、違反規(guī)則”); Return a/b;} } 對異常的針對性處理方式: Try { 需要被檢測的代碼; } Cathch(異常類 變量){ 異常處理代碼 } Finaly { 一定會被執(zhí)行的代碼。} 自定義異常: Java將常見的問題都封裝成了對象。 對于自定義項目中出現(xiàn)的問題,java并未給出對應(yīng)的描述,這時我們就需要按照面向?qū)ο蟮乃枷胱约和瓿蓪栴}的描述和封裝。 自定義異常: 需求:在我的程序中,進行除法運算,除數(shù)不可以為負(fù)數(shù)也不可以為0;對0這種情況,java中有對應(yīng)的描述,ArithmeticException 對于負(fù)數(shù),java中沒有。只有我們自己定義,定義一個類來對異常進行描述。 Class FuShuException extends Exception { Private int num;FuShuException(){} FuShuException(String message,int num){ Super(message);This.,num=num;} Public int getNum(){ Return num;} } Class Demo { Int div(int a,int b)throws FuShuException { If(b<0)Throw new FuShuException(“除數(shù)不可以為負(fù)數(shù)”);函數(shù)內(nèi)拋出異常,函數(shù)上一定要標(biāo)示。函數(shù)內(nèi)拋出是什么?函數(shù)上就標(biāo)示什么? 對方拋出什么異常,我就處理什么異常。Return a/b;} } Class ExceptionDemo2 { Public static void main(String[] aths){ Demo d=new Demo(); Try { Int num=d.div(4,-1);Sop(“num=”+num);} Cathc(FuShuException e){ Sop();e.printStackTrace();} Sop(“over”);} } 自定義應(yīng)用: 異常分兩種: 1、編譯被檢測的異常:Exception 這種異常通常都需要進行針對性的處理。 2、運行時發(fā)生的異常:RuntimeException 對于運行時異常一般是不編寫針對性的處理方式,如果該異常發(fā)生就讓程序停止,對程序進行修正。因為這種的出現(xiàn)往往已經(jīng)無法讓程序繼續(xù)運算了。 class Demo { int div(int a,int b)throws ArithmeticException { if(b==0) throw new ArithmeticException(“除數(shù)為零”); return a/b; } } class ExceptionDemo3 { public static void main(String[] args) { getIndex(null,4); } public static int getIndex(int[] arr,int key) { if(arr==null)//進行健壯性判斷。 throw new NullPointerException(“沒有具體的數(shù)組”); for(int x=0;x { if(arr[x]==key) return x; } return-1; } public static int getElement(int[] arr,int index) { if(arr==null) throw new NullPointerException(“沒有具體的數(shù)組實例”); if(index<0||index>=arr.length) throw new ArrayIndexOutOfBoundsException(“角標(biāo)越界”); return arr[index]; } }-------------------異常練習(xí): /* 需求: 畢老師用電腦上課。按照面向?qū)ο笏枷雭砻枋?。名詞提煉法 上課過程中出現(xiàn)的問題: 1、電腦藍屏了。 2、電腦冒煙了。 */ class LanPinException extends Exception { LanPinException(String message) { super(message); } } class MaoYanException extends Exception { MaoYanException(String message) { super(message); } } class NoPlanException extends Exception { NoPlanException(String message) { super(message); } } class Computer { private int state=2; public void run()throws LanPinException,MaoYanException { if(state==1) throw new LanPinException(“電腦藍屏了”); if(state==2) throw new MaoYanException(“電腦冒煙了”); System.out.println(“電腦運行”); } public void reset() { System.out.println(“電腦重啟”); state=0; } } class Teacher { private String name; private Computer cmpt; Teacher(String name) { cmpt=new Computer(); this.name=name; } public void prelect()throws NoPlanException//此處冒煙是電腦發(fā)生的,能再老師講課的功能出現(xiàn)這樣的異常么?所以拋出的對象不對,老師只能耽誤了講課的進度,所以此時是否應(yīng)該定義一個關(guān)于講課進度的類來封裝這個問題。 { try { cmpt.run(); System.out.println(name+“畢老師講課”); } catch(LanPinException e) { System.out.println(e.getMessage()); cmpt.reset(); prelect(); } catch(MaoYanException e)//這個功能我處理不了,因為冒煙不會了,這時候需要拋出。 { test(); //throw e;//因為處理不了,繼續(xù)往外拋。此時在講課方法上要聲明。此處也不能拋出這個異常。因為冒煙是電腦運行時的,不是老師講課的。 throw new NoPlanException(“課時無法繼續(xù)進行”); } } public void test() { System.out.println(“練習(xí)”); } } class ExceptionTest { public static void main(String[] args) { Teacher t=new Teacher(“畢老師”); try { t.prelect(); } catch(NoPlanException e) { System.out.println(“換人”); } } } //到底什么是拋什么處理? /* 自己能解決的就處理,處理不了就拋。 比如著火了,小火的時候自己可以處理,比如滅火器等 當(dāng)火勢大了,就處理不了,只能交給消防隊,自己要跑。 */ Day09總結(jié): 上午: 1、final關(guān)鍵字: Eg:代碼實現(xiàn): Class Fu { Final void method(){ //code...訪問低層代碼 } } Class Zi extends Fu { Void method() { Sop(“haha”);} } 以上代碼體現(xiàn)出繼承的弊端,因為父類的method的方法訪問了系統(tǒng)的低層代碼。當(dāng)子類對其覆寫,就不會去訪問父類的meth的方法,直接用自己的method這樣就出現(xiàn)了代碼的不嚴(yán)謹(jǐn)性,所以此時需要用final關(guān)鍵字進行修飾。注意為什么不把類加final修飾,因為可能該類中會出現(xiàn)很多功能。有些是不需要被覆寫的。有些是被調(diào)用的。所以只能根據(jù)自己所需對相應(yīng)的成員進行修飾。 2、Final的特點: 1、final是一個修飾符,可以修飾類、方法、變量(成員變量、局部變量) 2、Final修飾的類不可以被繼承。 3、Final修飾的方法不可以被覆蓋。 4、Final修飾的變量是一個常量,只能被賦值一次。是為了增強閱讀性,只要數(shù)據(jù)是固定的,就將這個數(shù)據(jù)用一個名稱來表示,并用final修飾。常量名稱都是大寫字母,多個單詞組成時用下劃線來分隔。 代碼體現(xiàn): Eg: Class Zi { Static final int num=90;//必須對變量進行初始化,不知道要最終化哪個值,所以必須對它進行初始化。加靜態(tài)也是一樣的,同樣的道理,并且被初始化,此時靜態(tài)和final沒有必然的聯(lián)系。當(dāng)變量被final修飾時,說明變量已經(jīng)是一個常量值,此時不能被修飾,可以用static來修飾。 Public stati double PI=3.14;Void method(){ Final int x=4; X=8; Sop(num);//既然是在操作一個固定的值。為什么不把4直接寫在此處,如果這樣做的的話,閱讀性極差,你根本就不知道它所代表什么?為了增強閱讀性,此時數(shù)據(jù)是不變化的,所以我們需要給它起個名字,并且用final來修飾。這樣的話它也是固定的不變的。 注意:被final修飾的數(shù)值只能被覆寫一次,并且修飾的常量名全部大寫,多個單詞組成時用下劃線進行分隔。Eg:final int PERSON_AGE=4;} } 3、抽象類: 特點: 1、沒有方法體的方法,稱為抽象方法,必須存放在抽象方法類中,抽象方法和抽象類必須用abstract關(guān)鍵字來修飾,2、抽象類不可以被實例化,為什么?因為調(diào)用抽象方法沒有意義?為什么?因為它連方法體都不存在? 3、抽象類必須由其子類將抽象類中的抽象方法都覆蓋后,其子類才可以被實例化,否則該子類還是抽象類。Eg: Abstract class Demo { Abstract void show();} Class SubDemo extends Demo Void show(){} //此時把父類中抽象方法覆蓋,此時才能被實例化。} 比如水果,它就是抽象的,不具體它包含各種各樣的水果,每種水果有它自己的體現(xiàn)。 抽象類涉及的問題? 1、抽象類中是否可以定義非抽象的方法? 可以 首先抽象類是一個類,類是用來描述事物,只不過描述事物過程中有些信息不具體,抽象類和一般類異同點: 相同:抽象類和一般類都用于描述事物,都可以定義成員。不同:抽象類中可以定義抽象成員函數(shù),(抽象要么修飾類要么修飾函數(shù))而一般類不可以。 抽象類不可以實例化,一般類可以實例化。 2、抽象類中是否有構(gòu)造函數(shù)? 有,而且抽象類雖然自身不可以被實例化,但是其子類覆蓋了所有的抽象方法后,是可以實例化的。所以抽象類的構(gòu)造函數(shù)是用于給其子類對象進行實例化。 3、抽象類通常都是一個父類? 是、因為需要子類去覆蓋父類中的抽象方法。代碼體現(xiàn): Abstract class Demo{ Abstract voif show1();Abstract void show2();} Abstract class SubDemo extends Demo { Void show1();} Class Test extends SubDmeo { Void show2();} 4、抽象類中可不可以不定義抽象方法? 可以;看上去沒有什么意義,其實有點意義,就是不讓這個類創(chuàng)建對象,為什么不讓創(chuàng)建? 代碼體現(xiàn): interface InterTest//這是一個測試接口,有4種測試方式。 { void test1();void test2();void test3();void test4(); } abstract class InterTestImpl implements InterTest//用這個類進行所有的空實現(xiàn)。但是創(chuàng)建對象是毫無意義的。所以用抽象。 { public void test1(){} public void test2(){} public void test3(){} public void test4(){} } class Test2 extends InterTestImpl { public void test2(){} } class Test3 extends InterTestImpl { public void test3(){} } /* class InterTestImpl implements InterTest { public void test2()// { sop(“testimpl test2”); } public void test1(){}//這樣做實現(xiàn)太麻煩。代碼重復(fù)。如何改進? public void test3(){} public void test4(){} } */ 5、抽象關(guān)鍵字 不可以和那些關(guān)鍵字共存? Final:修飾了類是一個最終類,不可以被繼承,然后abstract修飾的類必須是父類,需要被繼承、沖突、非法的修飾符組合,abstract 和final Static:抽象方法被static修飾,就具備了可以被類名直接調(diào)用的的特點,但是抽象方法被調(diào)用沒有意思。 Priavte:因為抽象方法被私有,無法被覆蓋。 代碼體現(xiàn): 雇員實例: 需求:公司中程序員有姓名、工號、薪水、工作內(nèi)容。 項目經(jīng)理除了姓名、工號、薪水、還有獎金、工作內(nèi)容 進行數(shù)據(jù)建模 做問題領(lǐng)域的分析就是找出問題領(lǐng)域的對象。 分析: 在這個問題領(lǐng)域中有兩個對象: 程序員: 屬性:姓名,工號,薪水 行為:工作內(nèi)容 項目經(jīng)理: 屬性:姓名、工號、薪水、獎金 行為:工作內(nèi)容。 這時候不能用項目經(jīng)理去繼承程序員。因為職能不同,但是有共性,只能抽取。 就有了員工: 屬性:姓名,工號,薪水 行為:工作內(nèi)容 */ abstract class Employee { private String name;private String id;private double pay;Employee(String name,String id,double pay){ this.name=name; this.id=id; this.pay=pay;} public abstract void work();//工作內(nèi)容是無法知道的。} class Programmer extends Employee { Programmer(String name,String id,double pay){ super(name,id,pay);} public void work(){ System.out.println(“code”);} } class Manager extends Employee { private double bonus;Manager(String name,String id,double pay){ super(name,id,pay); this.bonus=bonus;} public void work(){ System.out.println(“manage”);} } 4、接口: 格式:interface{} 表現(xiàn)特點: 1、里面的方法都是抽象的。 2、接口中的成員都有固定的修飾符,最常見的成員:全局常量抽象方法。只是最常見,不代表只有它們沒有其他的,全局常量,共有的不需要對象,直接用接口調(diào)用的,不可變的。 表現(xiàn)形式:Public static final 抽象方法:public abstract 3、接口的成員都是public的。 4、接口是不可以創(chuàng)建對象的。就相當(dāng)于是抽象的特殊表達形式。(但是有區(qū)別和抽象類) 5、類與類之間是繼承關(guān)系,類與接口之間是實現(xiàn)關(guān)系。 6、接口的出現(xiàn)可以多實現(xiàn),避免了單繼承的局限性。 7、一個類在繼承一個類的同時,還可以實現(xiàn)多個接口、8、接口與接口之間是繼承關(guān)系,而且可以多繼承,以為接口的方法都沒有主體。思想特點: 1、對外暴露的規(guī)則。 外設(shè)要介入計算機中,因為計算機外面提供了接口,這就是規(guī)則。 2、程序的功能擴展 3、降低了耦合性 4、用來多實現(xiàn) 結(jié)合電腦主板的思想進行闡述,它是個規(guī)則。對外提供的規(guī)則 它提高了我們功能的擴展性,降低了耦合性。主板和聲卡:主板使用規(guī)則,聲卡實現(xiàn)規(guī)則。 與抽象類的區(qū)別:抽象類有單繼承的局限性,接口沒有 5、java對多繼承記住改良,以多現(xiàn)實接口的方式來體現(xiàn)。差別:多繼承因為父類中有相功能時,會造成不確定性。為什么可以實現(xiàn)多實現(xiàn)? 因為繼承中父類的方法有方法體?這才是造成不確定性的根本原因,而此處是沒有方法體的。 代碼體現(xiàn): interface A { //int show();//這樣是不可以的。無法覆蓋。 void show();} interface B { // void method(); void show();//當(dāng)有重復(fù)的方法時。但是此時子類復(fù)寫它是可以的,為什么? //因為繼承中父類的方法有方法體。這才是造成不確定性的根本原 因。而 //此處是沒有方法體的。 } class C extends D implements A,B//多實現(xiàn)。此時c必須覆蓋兩個方法 { public void show(){} //public void method(){} } //一個類在繼承一個的類的時候還可實現(xiàn)多實現(xiàn) class D { public void function();} //接口之間是可以繼承,而且支持多繼承。 interface InterA { void showA();} interface InterB { void showB();} interface InterC extends InterA,InterB//為什么此處可以實現(xiàn)多繼承,因為方法沒有主體。 { void showC();} class InterfaceDemo2 { public static void main(String[] args) { C c=new C(); c.show(); System.out.println(“Hello World!”); } } 6、抽象類和接口之間的區(qū)別: 共性:它們都是不斷抽取出來的抽象非概念 區(qū)別: 1、抽象類只能被單繼承、接口可以被多實現(xiàn),避免了單繼承的局限性。 2、抽象類中可以定義抽象方法,和非抽象方法,它可以用于定義體系的基本共性的內(nèi)容。接口中只能定義抽象方法,它主要用于對象的功能的擴展。 3、抽象類是繼承關(guān)系,是is a關(guān)系,接口是實現(xiàn)關(guān)系是like a關(guān)系。 4、抽象類中的成員修飾符都是自定義的,接口中的修飾符都是固定的。記住:不要把接口狹義的理解為interface,應(yīng)該理解廣義些,就是對外提供的規(guī)則,凡是對外暴露的都可以是接口。 實現(xiàn)代碼: 1、abstract class 犬 { public abstract void 吃飯(); public abstract void 吼叫(); } interface 搜爆 { public void 搜爆(); } class 搜爆犬 extends 犬 implements 搜爆//這是即具備了犬的基本特性,又具備了搜爆功能。 { public void 搜爆(){} public void 吃飯(){} public void 吼叫(){} } class 搜爆貓 extends 貓 implements 搜爆 { public void 搜爆(){} } 記住: 類里面都是定義的一些基礎(chǔ)內(nèi)容,接口里面都是定義一些特性內(nèi)容,這樣的方便了對其進行擴展。 //抽煙的學(xué)生,抽煙是額外功能。 2、abstract class Student { abstract void study(); } interface Smoking { void smoke(); } class SomkeStudent extends Student implements Smoking { public void study(){} public void smoke(){} } //煙民。學(xué)生煙民 問題領(lǐng)域不同,對象的屬性和行為也不同。 abstract class Somker { abstract void smoke(); } interface Study { void study(); } class StudentSmoker extends Smoker implements Study { public void smoke(){} public void study(){} } 7、多態(tài):重點掌握 定義:某一類事物的多種存在形態(tài)。代碼實現(xiàn): class 動物 {} class 貓 extends 動物 { } 貓 x=new 貓(); 動物 y=new 貓();//父類的引用變量指向了其子類的對象。 多態(tài)在代碼中的體現(xiàn),父類或者接口的引用指向了自己的子類對象。 實現(xiàn)代碼: class Animal { abstract void eat(); } class Dog extends Animal { void eat(){ sop(“啃骨頭”);} void lookHome() { sop(“看家”);} } class Cat extends Animal { void eat(){ sop(“吃魚”);} void catchMouse(){ sop(“抓老鼠”);} } class Pig extends Animal { void eat(){ sop(“豬飼料”);} void gongdi(){ sop(“拱地”);} } class DuoTaiDemo { public static void main(String[] args){ //Cat c=new Cat(); //c.eat(); //Cat c1=new Cat(); //c1.eat(); //method(c); //method(c1); 重要知識點:----開發(fā)都用! Animal a=new Cat();//此處貓對象類型自動向上提升---向上轉(zhuǎn)型,當(dāng)指向使用體系基本功能時,可以向上轉(zhuǎn)型操作。 為什么體現(xiàn)多態(tài)性? 首先貓是一個實體,是一個貓類型,因為有了繼承,是動物中的一種,把這個實體稱之為動物也可以,所以它具備了兩種形態(tài),貓和動物。這便是體現(xiàn)了多態(tài)性。 //一旦向上轉(zhuǎn)型,貓就不是貓了,已經(jīng)是動物類型了。 a.catchMouse();//編譯失敗。 但是現(xiàn)在想執(zhí)行貓的抓老鼠的功能怎么辦? 向下轉(zhuǎn)型: Cat c=(Cat)a;//向下轉(zhuǎn)型。當(dāng)使用子類對象中的特有內(nèi)容時,才做向下轉(zhuǎn)型。 c.eat(); c.catchMouse();//此時是可以實現(xiàn)貓的抓老鼠的功能的。 總結(jié):在多態(tài)轉(zhuǎn)型中,至始至終只有子類對象做著類型的變化。 method(new Cat()); } public static void method(Animal a)//Animal a=new Cat();{ 重點知識點:instanceof if(a instanceof Cat)//對象instanceof 類型 判斷具體對象是否是指定的類型。 { Cat c=(Cat)a;//編譯通過,但是不能運行,此時類型轉(zhuǎn)換異常classCastException; //此時為了程序的嚴(yán)謹(jǐn)性,需要對傳入的的對象進行判斷。 c.catchMouse(); } else if(a instanceof Dog) { Dog d=(Dog)a; d.lookHome(); } a.eat(); 總結(jié): instanceof是一個關(guān)鍵字,用于判斷對象的類型。什么時候用? 當(dāng)進行向下轉(zhuǎn)型時,先判斷該對象是否符合被轉(zhuǎn)成的子類型。 } } 8、重點理解: 1、多態(tài)的好處:提高了代碼的擴展性,有了多態(tài),前期設(shè)計好的內(nèi)容可以使用后期出現(xiàn)的子類內(nèi)容,對于指揮對象做事情這件事情,如果對象很多,指揮起來很麻煩,抽取對象的共性類型,對該類型的事物進行指揮就會變的很簡單。 2、多態(tài)的前提: 1、必須要有關(guān)系:繼承、實現(xiàn)。 2、必須有覆蓋的操作。 3、多態(tài)的弊端:前期的程序雖然可以使用后期出現(xiàn)的子類內(nèi)容,但是只能使用子類覆蓋父類中的內(nèi)容,不能使用子類中的特有內(nèi)容。第二篇:黑馬程序員java培訓(xùn)就業(yè)班筆記:day05總結(jié)
第三篇:黑馬程序員java培訓(xùn)就業(yè)班筆記:day06總結(jié)
第四篇:黑馬程序員java培訓(xùn)就業(yè)班筆記:day10總結(jié)
第五篇:黑馬程序員java培訓(xùn)就業(yè)班筆記:day09總結(jié)