說說抽象和接口的異同
補充定義:
抽象類,即一個包含抽象方法的類,類中的抽象方法以abstract來修飾。
abstract只能修飾類和方法,不能修飾變量。
接口,一個方法的集合,接口中所有的方法都沒有方法體,且方法都是以public abstract默認修飾,其中abstract可以省略。public abstract也可以省略
接口是程序的功能擴展,用來多實現。
相同點:
抽象類和接口都不能被實例化,只有接口的實現類或抽象類的子類實現了抽象類或接口中的所有抽象方法之後才能被實例化。
不同點
1。從繼承關係上來說,
抽象類類與類之間屬於單繼承,接口與接口屬於多繼承,類可以實現接口;
2。從方法上來說,
抽象類中可以包含抽象方法(沒有方法體),也可以不包含(聲明該類不能被實例化而已),可以存在有其他實現的普通方法。抽象方法不能用private static synchronized native修飾。子類繼承抽象類,要麼實現抽象類中所有抽象方法,要麼自己也是抽象類,實現部分抽象方法;
接口中的方法都是以public abstract默認修飾的,因此都不能有方法體,不能有普通方法。實現類必須實現接口中的所有方法,否則爲抽象類。其中,public abstract可以省略abstract,也可以public abstract都省略。
3。從成員變量來說。
抽象類中可以有普通變量,可以有靜態變量等各種類型;
接口中的變量只能被public static final修飾,並且必須要賦初值。
異常及異常處理方法(try throws)
Java提供了兩種錯誤的異常,分別是Error和Exception,且它們擁有共同的父類Throwable,這使得異常體系中所有類以及對象都具備可拋性。
Error表示程序在運行期間出現了嚴重的錯誤,且該錯誤是不可恢復的,這將導致程序的終止。由於編譯器不會檢查Error是否被處理,因此一般對Error不作捕獲。
Exception表示可恢復的異常,是編譯器可以捕獲到的。包含兩種,檢測時異常和運行時異常。
異常分類
檢測時異常:所有繼承自Exception且不是運行時異常的都是檢測時異常。如最常見的IO異常和SQL異常等。發生在編譯階段,Java編譯器會強制程序去捕獲異常。
運行時異常:編譯器不對其進行捕獲處理。如果不對其進行處理,將由JVM來進行處理。如NullPointException,ClassCastException,ArrayIndexOutOfBoundsException,BufferOverflowException,ArithmeticException等。函數內拋異常,函數上不用聲明,編譯照樣通過。
處理異常
對於異常的處理,通常有兩種,一種是在函數上聲明異常,用throws拋出異常;一種是在函數內拋異常,用try catch finally的組合等。
//函數上用throws聲明異常
public static void getException() throws ArithmeticException{
System.out.println(10/0);
}
//函數內try catch處理異常
public static void testException(){
try {//函數運算內容
System.out.println(10/0);
} catch (Exception e) {//發生異常時的處理
throw new RuntimeException("除數爲0,出現異常");
}finally{
.....//一定會執行的內容,如資源的關閉等
}
}
對於try catch finally組合,有以下幾種:
try catch(try catch catch…)
try finally;
try catch finally(try catch catch…finally)
其中,多個catch時,最上層的是子類,父類都位於最下層,如有Exception,則將位於最後一個catch
try catch finally中的return
try中有return,finally中沒有,且不出現異常
public class Test1{
public static void main(String[] args) {
System.out.println(testException());
}
public static int testException(){
int a=1;
int b=10;
try {
System.out.println("try");
return a+b;
}catch (ArithmeticException e) {
System.out.println("catch");
return a+b+10;
}catch (Exception e) {
// TODO: handle exception
}finally{
a=a+10;
System.out.println("finally");
}
return 0;
}
}
//執行結果:
//try
//finally
//11
如上代碼所示,try中返回的是a+b,但finally是一定要執行的,如果return是在finally之後執行,那麼a=a+10後a變爲11,這時返回應該是21,而結果卻是11。這說明,當try中有return且不拋異常,而finally中沒有return時,在try遇到return時先保存返回值,再去執行finally,執行完再返回到try中返回先前保存的值。
如果try中此時拋異常,如令a=0,且try中 return b/a;結果如下:
try
catch
finally
20
當try中出現異常,catch中return的返回值也是暫存了,執行完finally之後再返回。
如果finally中也有返回值呢?!
public static int testException(){
int a=0;
int b=10;
try {
System.out.println("try");
return b/a;
}catch (ArithmeticException e) {
System.out.println("catch");
return ++a+1;
}finally{
System.out.println("finally");
return a+30;
}
}
/////執行結果
try
catch
finally
31
在try中拋異常,進入catch,此時return返回值應該是爲1,a值爲1,但由於finally存在,還得執行finally,結果finally中也有return,返回結果爲31。這裏,就將catch中的返回值進行了覆蓋。即finally中有返回值時,最終返回的是finally中的返回值。
異常子父類覆蓋情況。
子類拋異常必須是父類的子類或子集。父類不拋異常,子類只能try catch.
在try catch中如果拋檢測時異常,都得以try catch再包裹起來。如果是運行時異常,直接拋出即可。且try中的任何異常都會進入catch進行處理。
如果方法是沒有返回值的,finally中也可以直接拋異常,否則由於拋異常之後return不執行,導致檢測時不能通過。如果try中只拋異常,也會出現這種結果。
Object類有哪些方法?
除此之外,還有被隱藏的finalize和clone,總共11個方法。
判斷對象是否相等 equals、hashCode、==
==:如果是基本數據類型,則直接比較兩值是否相等;如果是引用數據類型,則比較的是兩個值的引用地址。
equals:Object類中的equals是直接使用“==”來比較兩個對象的。所以如果對equals方法沒有複寫的話,比較的是兩對象的引用地址。像String Date等類,都複寫了equals方法,最終比較的是二者的內容。
hashCode:Object類方法,也是用來判斷兩個對象是否相等的,它是返回對象在內存中地址轉換成的一個int值。如果沒有重寫hashCode,任何對象的hashCode都是不相等的。如果兩對象引用是相同的,則hashCode也是一樣的。String等類同樣對其進行了複寫。
equals和hashCode區別(**可以從hashmap底層實現來看)
如果equals返回值爲true,那麼hashCode一定相等;如果equals返回爲false,那麼hashCode可能相等也可能不等。
hashCode不相等,那麼equals肯定爲false;如果hashCode相等,equals可能爲true也可能爲false。
這個我們可以從散列角度考慮,不同的對象計算哈希碼時可能會發生衝突。某種程度上,hashCode比equals效率高
例如hashmap底層實現,查找Key時,先對其進行hash算法得到哈希值,如果hash值相同,再去比較key是否相等,key相等才能說找到了正確的結果。如果hash值不相等,那麼肯定在找不到相等的key。
包裝類的一些小知識
int 跟包裝類做==比較時,只比較數值大小,數值大小相等即爲true;
Integer m=數值的效果等同於Integer m=Integer.valueOf(數值),
valueOf會將常用的值(-128 to 127)cache起來。當i值在這個範圍時,會比用構造方法Integer(int)效率和空間上更好。Long也是。數值在-128-127之間時,裝箱後的Integer對象會重用,(直接在緩存中找);超過此範圍,裝箱後的Integer對象不會重用;
new Integer(數值),總會new一個對象,而且不是new緩存中的對象,==比較時,數值大小相等也會false。
public static void main(String[] args) {
//涉及到數值重用,數據在-128-127的情況
int x1=59;
Integer x2=59;
Integer x3=Integer.valueOf(59);
Integer x4=new Integer(59);
//int和包裝類作==比較,只比較數值大小
//(就算是new也是比較大小)
System.out.println("1-2"+(x1==x2));//true
System.out.println("1-3"+(x1==x3));//true
System.out.println("1-4"+(x1==x4));//true
//Integer m=數值的效果等同於Integer m=Integer.valueOf(數值)
//(-128-127內都會重用緩存中的值)
System.out.println("2-3"+(x2==x3));//true
//new對象,new的是緩存中的對象,數值相等也爲false
System.out.println("2-4"+(x2==x4));//false
System.out.println("3-4"+(x3==x4));//false
System.out.println("==============");
//數值不在-128-127的情況
int y1=200;
Integer y2=200;
Integer y3=Integer.valueOf(200);
Integer y4=new Integer(200);
//int比較值,仍成立
System.out.println("1-2"+(y1==y2));//true
System.out.println("1-3"+(y1==y3));//true
System.out.println("1-4"+(y1==y4));//true
//不會重用,Integer.valueOf(數值)相當於new Integer,因此不會和Integer m=數值 相等。
System.out.println("2-3"+(y2==y3));//false
//new對象,都不會相等
System.out.println("2-4"+(y2==y4));//false
System.out.println("3-4"+(y3==y4));//false
}
getClass、toString方法
這兩個方法都是屬於輔助方法。
getClass返回的是一個Class對象,後面可以跟class類的方法,用的是誰的構造函數,那麼getClass返回的就是誰的類型。getClass經常用於Java反射機制。
toString方法返回的是一個string對象,用來標識自己。
clone finalize方法
clone:使用clone可以用來複制一個對象,會在單獨的博文中分析該方法。
finalize:JVMGC機制時對對象回收的一個方法,判斷對象是否真的無法存活,如果在該方法過程中對象還能和引用鏈發生關係,則對象不會被回收。該方法一個對象只能調用一次。
wait wait(long) wait(long,int) notify notifyAll
這五種方法都與多線程的喚醒阻塞有關係。其中wait表示讓正在進行的線程暫停執行,釋放對象鎖,進入等待阻塞狀態,直到被其他的線程喚醒或者是等待阻塞超時才重新進入就緒狀態等待獲取鎖,。與之匹配的就是喚醒,即notify隨機喚醒阻塞的線程,notifyAll喚醒的是所有阻塞的線程。
sleep是不釋放資源,等待一定時間繼續執行。
說說wait和sleep的區別
1。原理不同。
sleep是Thread的靜態類,是線程用來控制自身流程的。它會使得線程暫停執行一段時間,將執行機會交給其他線程,等到時間一到就自動“喚醒”繼續執行;
wait是Object方法,用於線程間的通信。它使得正在執行的線程放棄執行機會,進入阻塞狀態,讓其他線程去爭奪執行權。直到超時或者被喚醒才重新進入就緒狀態去爭奪執行權。
2。對鎖的處理機制不同。
sleep不釋放鎖,而wait會釋放鎖。
3。使用區域不同。
sleep可以放在任何地方使用,而wait由於其特殊性,只能放在同步控制方法或同步塊中執行。
4。對於異常。
sleep必須捕獲異常,如InterruptedException。wait等不用捕獲異常,但要進行try catch處理,否則會在運行時拋出IllegalMonitorStateException。
線程狀態:創建,就緒,運行,阻塞,停止。
既然談到線程,說說線程創建方式
線程創建的方式有兩種,一種是繼承Thread類,一種是實現runnable接口。由於接口的多繼承和擴展性,一般來說,使用實現runnable接口形式更好。
什麼是進程?什麼是線程?什麼是多進程?什麼是多線程?爲什麼要有多進程和多線程?
進程:操作系統進行資源分配的單位;正在運行的程序。
線程:進程中獨立操作的執行單元。
多進程:多進程是指同時運行多種程序。或者一個程序多個進程。
多線程:多線程是爲了使得多個線程並行的工作以完成多項任務,以提高系統的效率。線程是在同一時間需要完成多項任務的時候被實現的。
談談什麼是死鎖,如何避免死鎖
死鎖,多線程競爭共享資源導致的無限期等待。
四個必要條件:互斥條件,不可搶佔條件,佔有且申請條件,循環等待條件。
如何避免死鎖:安全序列,銀行家算法。
線程池介紹,幾個線程池的區別
線程池7個參數的解釋,
Executors.newCachedThreadPool(); //創建一個緩衝池,緩衝池容量大小爲Integer.MAX_VALUE
Executors.newSingleThreadExecutor(); //創建容量爲1的緩衝池
Executors.newFixedThreadPool(int); //創建固定容量大小的緩衝池
Java如何保證原子性的
鎖(lock和unlock來實現原子性的)和循環CAS(共享變量)。
對於線程安全的實現,有三種,同步互斥,非阻塞同步,無同步。其中涉及到鎖的爲同步互斥,涉及到synchronized鎖,如果加鎖解鎖太過頻繁,用戶態到核心態的一個切換會消耗各種資源。因此對鎖進行一系列的優化,如自旋鎖,自適應自旋鎖,鎖消除,鎖加粗,輕量級鎖,偏向鎖和重量級鎖。
說說反射機制
反射機制,在程序運行時動態的去獲取一個已知類名的所有內部信息,包括對象,方法,字段等。
反射機制可以去操縱對象的。
對設計模式有了解麼
單例設計模式,必須掌握的。
單例設計模式怎麼實現的
私有構造函數,私有自定義實例對象,公有訪問方法。
爲什麼要聲明靜態單例對象
首先,單例模式決定了你不能在其他地方創建對象,而是通過類中提供的公有訪問方法去訪問類中的那個自定義對象。
而程序調用類中的方法只有兩種,一種是創建類的一個對象,用對象去調用方法;構造函數私有化以後這種方法就不合適了。
第二種是通過類名.方法名來進行調用。這樣訪問方法必須是靜態的,而靜態方法不能訪問非靜態成員變量,因此類中自定義的實例變量必須是靜態的。
static關鍵字
作用,修飾成員(成員變量和成員函數)
特點;(隨着類的加載而加載,優先於對象存在,被所有對象共享,可以直接被類名調用)
和實例變量的區別(存放位置,生命週期)(實例變量就是成員變量,非static修飾的)(方法區,堆內存)
利弊:好處是對共享數據進行單獨存儲,節省空間,沒必要每個對象都存一份,可以直接被類名調用;
壞處就是其生命週期過長,對於一些使用較少的,浪費了空間。
訪問特點:靜態的只能訪問靜態的,非靜態的既可以訪問非靜態,也可以訪問靜態的。
知道final關鍵字麼?
修飾類。變量。函數。 變量爲成員變量,靜態變量,局部變量
類不可被繼承,方法不可被重寫,變量不可改變
final finally finalize的作用
關鍵字,異常處理,垃圾回收時調用來判斷對象是否需要被回收