咱們知道finally{}中的語句是必定會執行的,那麼這個可能正常脫口而出就是return以前,return以後可能就出了這個方法了,鬼知道跑哪裏去了,但更準確的應該是在return中間執行,請看下面程序代碼的運行結果:java
public classTest { public static void main(String[]args) { System.out.println(newTest().test());; } static int test() { intx = 1; try { return x; } finally { ++x; } } }
執行結果以下:mysql
1
運行結果是1,爲何呢?主函數調用子函數並獲得結果的過程,比如主函數準備一個空罐子,當子函數要返回結果時,先把結果放在罐子裏,而後再將程序邏輯返回到主函數。所謂返回,就是子函數說,我不運行了,你主函數繼續運行吧,這沒什麼結果可言,結果是在說這話以前放進罐子裏的。面試
異常表示程序運行過程當中可能出現的非正常狀態,運行時異常表示虛擬機的一般操做中可能遇到的異常,是一種常見運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,可是並不要求必須聲明拋出未被捕獲的運行時異常。算法
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
error 表示恢復不是不可能但很困難的狀況下的一種嚴重問題。好比說內存溢出。不可能期望程序能處理這樣的狀況。exception表示一種設計或實現問題。也就是說,它表示若是程序運行正常,從不會發生的狀況。sql
異常是指java程序運行時(非編譯)所發生的非正常狀況或錯誤,與現實生活中的事件很類似,現實生活中的事件能夠包含事件發生的時間、地點、人物、情節等信息,能夠用一個對象來表示,Java使用面向對象的方式來處理異常,它把程序中發生的每一個異常也都分別封裝到一個對象來表示的,該對象中包含有異常的信息。編程
Java對異常進行了分類,不一樣類型的異常分別用不一樣的Java類表示,全部異常的根類爲java.lang.Throwable。數組
Throwable下面又派生了兩個子類:緩存
系統異常是軟件自己缺陷所致使的問題,也就是軟件開發人員考慮不周所致使的問題,軟件使用者沒法克服和恢復這種問題,但在這種問題下還可讓軟件系統繼續運行或者讓軟件掛掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException);安全
普通異常是運行環境的變化或異常所致使的問題,是用戶可以克服的問題,例如,網絡斷線,硬盤空間不夠,發生這樣的異常後,程序不該該死掉。服務器
java爲系統異常和普通異常提供了不一樣的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,因此普通異常也稱爲checked異常,而系統異常能夠處理也能夠不處理,因此,編譯器不強制用try..catch處理或用throws聲明,因此係統異常也稱爲unchecked異常。
"=="
對於基本類型和引用類型 == 的做用效果是不一樣的,以下所示:
String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.out.println(x.equals(y)); // true System.out.println(x.equals(z)); // true
由於 x 和 y 指向的是同一個引用,因此 == 也是 true,而 new String()方法則重寫開闢了內存空間,因此 == 結果爲 false,而 equals 比較的一直是值,因此結果都爲 true。
equals
equals 本質上就是 ==,只不過 String 和 Integer 等重寫了 equals 方法,把它變成了值比較。看下面的代碼就明白了。
首先來看默認狀況下 equals 比較一個有相同值的對象,代碼以下:
class Cat { public Cat(String name) { this.name = name; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Cat c1 = new Cat("葉痕秋"); Cat c2 = new Cat("葉痕秋"); System.out.println(c1.equals(c2)); // false
輸出結果出乎咱們的意料,居然是 false?這是怎麼回事,看了 equals 源碼就知道了,源碼以下:
public boolean equals(Object obj) { return (this == obj); }
原來 equals 本質上就是 ==。
那問題來了,兩個相同值的 String 對象,爲何返回的是 true?代碼以下:
String s1 = new String("葉子"); String s2 = new String("葉子"); System.out.println(s1.equals(s2)); // true
一樣的,當咱們進入 String 的 equals 方法,找到了答案,代碼以下:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
原來是 String 重寫了 Object 的 equals 方法,把引用比較改爲了值比較。
總結
== 對於基本類型來講是值比較,對於引用類型來講是比較的是引用;而 equals 默認狀況下是引用比較,只是不少類從新了 equals 方法,好比 String、Integer 等把它變成了值比較,因此通常狀況下 equals 比較的是值是否相等。
java的集合有兩類,一類是List,還有一類是Set。前者有序可重複,後者無序不重複。當咱們在set中插入的時候怎麼判斷是否已經存在該元素呢,能夠經過equals方法。可是若是元素太多,用這樣的方法就會比較滿。
因而有人發明了哈希算法來提升集合中查找元素的效率。 這種方式將集合分紅若干個存儲區域,每一個對象能夠計算出一個哈希碼,能夠將哈希碼分組,每組分別對應某個存儲區域,根據一個對象的哈希碼就能夠肯定該對象應該存儲的那個區域。
hashCode方法能夠這樣理解:它返回的就是根據對象的內存地址換算出的一個值。這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一會兒能定位到它應該放置的物理位置上。若是這個位置上沒有元素,它就能夠直接存儲在這個位置上,不用再進行任何比較了;若是這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。這樣一來實際調用equals方法的次數就大大下降了,幾乎只須要一兩次。
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
不對,兩個對象的 hashCode() 相同,equals() 不必定 true。
代碼示例:
String str1 = "keep"; String str2 = "brother"; System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode())); System. out. println(str1. equals(str2));
執行結果:
str1:1179395 | str2:1179395 false
代碼解讀:很顯然「keep」和「brother」的 hashCode() 相同,然而 equals() 則爲 false,由於在散列表中,hashCode() 相等即兩個鍵值對的哈希值相等,然而哈希值相等,並不必定能得出鍵值對相等。
泛型是Java SE 1.5以後的特性, 《Java 核心技術》中對泛型的定義是:
「泛型」 意味着編寫的代碼能夠被不一樣類型的對象所重用。
「泛型」,顧名思義,「泛指的類型」。咱們提供了泛指的概念,但具體執行的時候卻能夠有具體的規則來約束,好比咱們用的很是多的ArrayList就是個泛型類,ArrayList做爲集合能夠存放各類元素,如Integer, String,自定義的各類類型等,但在咱們使用的時候經過具體的規則來約束,如咱們能夠約束集合中只存放Integer類型的元素,如
List<Integer> iniData = new ArrayList<>()
使用泛型的好處?
以集合來舉例,使用泛型的好處是咱們沒必要由於添加元素類型的不一樣而定義不一樣類型的集合,如整型集合類,浮點型集合類,字符串集合類,咱們能夠定義一個集合來存放整型、浮點型,字符串型數據,而這並非最重要的,由於咱們只要把底層存儲設置了Object便可,添加的數據所有均可向上轉型爲Object。 更重要的是咱們能夠經過規則按照本身的想法控制存儲的數據類型。
面向對象的編程語言有封裝、繼承 、抽象、多態等4個主要的特徵。
注意:在使用多態後的父類引用變量調用方法時,會調用子類重寫後的方法。
定義格式:父類類型 變量名=new 子類類型();
重寫(Override)
從字面上看,重寫就是 從新寫一遍的意思。其實就是在子類中把父類自己有的方法從新寫一遍。子類繼承了父類原有的方法,但有時子類並不想原封不動的繼承父類中的某個方法,因此在方法名,參數列表,返回類型(除過子類中方法的返回值是父類中方法返回值的子類時)都相同的狀況下, 對方法體進行修改或重寫,這就是重寫。但要注意子類函數的訪問修飾權限不能少於父類的。
public class Father { public static void main(String[] args) { // TODO Auto-generated method stub Son s = new Son(); s.sayHello(); } public void sayHello() { System.out.println("Hello"); } } class Son extends Father{ @Override public void sayHello() { // TODO Auto-generated method stub System.out.println("hello by "); } }
重寫 總結:
1.發生在父類與子類之間
2.方法名,參數列表,返回類型(除過子類中方法的返回類型是父類中返回類型的子類)必須相同
3.訪問修飾符的限制必定要大於被重寫方法的訪問修飾符(public>protected>default>private)
4.重寫方法必定不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的檢查型異常
重載(Overload)
在一個類中,同名的方法若是有不一樣的參數列表(參數類型不一樣、參數個數不一樣甚至是參數順序不一樣)則視爲重載。同時,重載對返回類型沒有要求,能夠相同也能夠不一樣,但不能經過返回類型是否相同來判斷重載。
public class Father { public static void main(String[] args) { // TODO Auto-generated method stub Father s = new Father(); s.sayHello(); s.sayHello("wintershii"); } public void sayHello() { System.out.println("Hello"); } public void sayHello(String name) { System.out.println("Hello" + " " + name); } }
重載 總結:
1.重載Overload是一個類中多態性的一種表現
2.重載要求同名方法的參數列表不一樣(參數類型,參數個數甚至是參數順序)
3.重載的時候,返回值類型能夠相同也能夠不相同。沒法以返回型別做爲重載函數的區分標準
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
java中提供瞭如下四種建立對象的方式:
public class Test { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(2); Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ Integer integer = iterator.next(); if(integer==2) list.remove(integer); } } }
執行上段代碼是有問題的,會拋出ConcurrentModificationException
異常。
緣由:調用list.remove()
方法致使modCount
和expectedModCount
的值不一致。
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
解決辦法:在迭代器中若是要刪除元素的話,須要調用Iterator
類的remove
方法。
public class Test { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(2); Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ Integer integer = iterator.next(); if(integer==2) iterator.remove(); //注意這個地方 } } }
相同點:
不一樣點:
什麼是fail-fast?
就是最快的時間能把錯誤拋出而不是讓程序執行。
Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。
ConcurrentHashMap將整個Map分爲N個segment(相似HashTable),能夠提供相同的線程安全,可是效率提高N倍,默認N爲16。
HashMap能夠經過下面的語句進行同步:
Map m = Collections.synchronizeMap(hashMap);
按功能來分:輸入流(input)、輸出流(output)。
按類型來分:字節流和字符流。
字節流和字符流的區別是:字節流按 8 位傳輸以字節爲單位輸入輸出數據,字符流按 16 位傳輸以字符爲單位輸入輸出數據。
一、定義:
反射機制是在運行時,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意個對象,都可以調用它的任意一個方法。在java中,只要給定類的名字,就能夠經過反射機制來得到類的全部信息。
這種動態獲取的信息以及動態調用對象的方法的功能稱爲Java語言的反射機制。
二、哪裏會用到反射機制?
jdbc就是典型的反射
Class.forName('com.mysql.jdbc.Driver.class');//加載MySQL的驅動類
這就是反射。如hibernate,struts等框架使用反射實現的。
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
第一步:獲取Class對象,有4種方法: 1)Class.forName(「類的路徑」); 2)類名.class 3)對象名.getClass() 4)基本類型的包裝類,能夠調用包裝類的Type屬性來得到該包裝類的Class對象
1)Class:表示正在運行的Java應用程序中的類和接口 注意: 全部獲取對象的信息都須要Class類來實現。 2)Field:提供有關類和接口的屬性信息,以及對它的動態訪問權限。 3)Constructor:提供關於類的單個構造方法的信息以及它的訪問權限 4)Method:提供類或接口中某個方法的信息
優勢:
一、可以運行時動態獲取類的實例,提升靈活性;
二、與動態編譯結合
缺點:
一、使用反射性能較低,須要解析字節碼,將內存中的對象進行解析。
解決方案:
一、經過setAccessible(true)關閉JDK的安全檢查來提高反射速度;
二、屢次建立一個類的實例時,有緩存會快不少
三、ReflectASM工具類,經過字節碼生成的方式加快反射速度
二、相對不安全,破壞了封裝性(由於經過反射能夠得到私有方法和屬性)
Java Io 流共涉及 40 多個類,這些類看上去很雜亂,但實際上頗有規則,並且彼此之間存在很是緊密的聯繫, Java I0 流的 40 多個類都是從以下 4 個抽象類基類中派生出來的。
按操做方式分類結構圖: