java面試筆記
JAVA面試大綱
1、Java程序執行過程
一個java程序的編譯和執行過程如下:
(一).java文件 -------編譯-----> .class文件
(二)類加載器負責加載各個字節碼文件(.class)
(三)加載完.class文件,由執行引擎執行,在執行過程中,需要運行時數據區提供數據
2、JVM內存管理
JVM將內存劃分為6個部分:PC寄存器(程序計數器)、虛擬機棧、堆、方法區、運行時常量池、本地方法棧
PC寄存器(程序計數器): 用於記錄當前線程運行時的位置,每一個線程都有一個獨立的程序計數器。線程的阻塞、恢復、掛起等一系列操作都需要程序計數器的參與、因此必須是線程私有的。
java虛擬機棧: 在創建線程時創建,用來存儲棧幀,因此也是線程私有的。java程序中的方法在執行時,會創建一個棧幀,用來存儲方法運行時的臨時數據與中間結果,包括局部變量表、操作數棧、動態鏈接、方法出口等信息。這些棧幀就存儲在棧中。如果棧深度大於虛擬機允許的最大深度,則拋出StackOverflowError異常。
局部變量表:方法的局部變量列表,在編譯時就被寫入.class文件
操作數棧:int x = 1;就需要將1壓入操作數棧,再將1賦值給變量x
?
java堆: java堆被所有線程共享,堆的主要作用就是存儲對象。如果堆空間不夠,但擴展時又申請不到足夠的內存時,則拋出OutOfMemoryError異常。
StackOverflowError | OutOfMemoryError |
---|---|
java棧 | java堆 |
棧深度超過範圍了(比如:遞歸層數太多了) | 內存空間不夠了(需要及時釋放內存) |
- 方法區: 方法區被各個線程共享,存放了要加載的信息(如類名、修飾符)、類中的靜態變量、final定義的常量、類中的field、運行時常量池、方法信息,當開發人員調用類對象中的getName,isInterface等方法來獲取信息時,這些數據來源於方法區。方法區是全局共享的,在一定條件下它也會被GC。當方法區使用的內存超過它允許的大小時,就會拋出OutOfMemory: PermGen Space異常(解決辦法:加大內存,)。在Hotspot虛擬機中,這塊區域對應的是Permanent Generation(持久代),一般的,方法區上執行的垃圾收集是很少的,因此方法區又被稱為永久代的原因之一,但這也不代表著方法區上完全沒有垃圾收集,其上的垃圾收集主要是針對常量池的內存回收和對已加載類的卸載。
- 本地方法棧: 本地方法棧的主要作用就是支持native方法,比如在ava中調用C/C++。
3、GC回收機制
- 哪些內存需要回收?
- 什麽時候開始回收?
- 怎麽回收?
(1)哪些內存需要回收
- java堆、方法區的內存
線程私有 | 線程共享 |
---|---|
程序計數器、虛擬機棧、本地方法棧 | java堆、方法區 |
隨線程生而生,隨線程去而去。線程分配多少內存都是有數的,當線程銷毀時,內存就被釋放了 | 堆和方法區的內存都是動態分配的,所以也需要動態回收。這部分內存的回收依賴GC完成 |
(2)什麽時候回收?
引用計數法
可達性分析
一、引用計數法
給對象添加一個引用計數器,每當一個地方引用它時,計數器加一。反之每當一個引用失效時,計數器減一,當計數器為0時,則表示對象不被引用。
舉個例子:
Object a = new Object(); //a的引用計數為1
a = null; //a的引用計數為0,等待GC回收
但是,引用計數法不能解決對象之間的循環引用,見下例
Object a = new Object(); //a的引用計數為1
Object b = new Object(); //b的引用計數為1
a.next = b; //a的引用計數為2
b.next = a; //b的引用計數為2
a = null; //a的引用計數為1,盡管已經顯示的將a賦值為null,但是由於引用計數為1,GC無法回收a
b = null; //b的引用計數為1,同理,GC也不回收b
? 二、可達性分析
設立若幹根對象(GC Root),
沒有一條從根到Object4和Object5的路徑,說明這兩個對象到根是不可達的,可以被回收。
補充:java中,可以作為GC Root的對象包括:
java虛擬機棧中引用的對象
方法區中的靜態變量引用的對象
方法區中常量引用的對象
本地方法棧中引用的對象
三、怎麽回收
- 標記——清除算法
- 復制算法
- 分代算法
(1)、標記——清除算法
遍歷所有的GC Root,分別標記可達的對象和不可達的對象,然後將不可達的對象回收。
缺點是:效率低,回收得到的空間不連續
(2)、復制算法
將內存分為兩塊,每次只使用一塊,當這一塊內存滿了,就將還存貨的對象復制到另一塊上,並且嚴格按照內存地址排列,然後把已使用的那塊內存統一回收。
優點是:能夠得到連續的內存空間
缺點是:浪費了一半內存
(3)分代算法
在java中,把內存中的對象按生命長短分為:
- 新生代:活不了多久就go die了,比如局部變量
- 老年代:老不死的,活的久但也會go die,比如一些生命周期長的對象
- 永久帶:千年烏龜老王八,不死,比如加載的class信息
有一點需要註意:新生代和老年代存儲在java虛擬機堆上:永久代存儲在方法區上
回收方法 | |
---|---|
新生代 | 使用復制算法 |
老年代 | 使用標記——清除算法、標記——整理算法 |
永久代 | —————————— |
(4)、標記——整理算法
標記過程與“標記——清楚算法一樣,但後續步驟不是直接對可回收對象進行清理,而是讓不可回收對象向邊移動,將端邊界以外的內存清理”
註意:
堆區是理解java GC機制最重要的區域,在JVM所管理的內存中,堆區是最大的一塊,也是java GC機制所管理的主要內存區域,堆區由所有線程共享,在虛擬機啟動時創建。堆區用來存儲對象實例及數組值,可以認為java中所有通過java創建的對象都在此分配。
為了讓內存回收更加高效,從Sun JDK1.2開始對堆采用了分代管理方式,如下圖所示:
年輕代
對象在被創建時,內存首先是在年輕代 上進行分配(註意,大對象可以直接在老年代上分配)。當年輕代需要回收時會觸發Minor GC (也稱作 Young GC)
年輕代由Eden Space和兩塊相同大小的Survivor Space(又稱S0和S1)構成,可通過-Xmn參數來調整新生代大小。年輕代的Eden區內存是連續的,所以其分配非常快,同樣Eden區的回收也非常快(因為大部分情況下Eden區對象存活時間非常短,而Eden區采用的復制回收算法,此算法在存活對象比例很少的情況下非常高效)
如果在執行垃圾回收之後,仍沒有足夠的內存分配,也不能再擴展,將會拋出OutOfMemoryError: java Heap Space異常
老年代
老年代用於存放在年輕代中經過多次垃圾回收仍然存活的對象,可以理解為老一點的對象,例如緩存對象;新建的對象也可能在老年代上直接分配內存,這裏有兩種情況:一種為大對象,可以通過啟動參數設置-XX:PretenureSizeThreshold=1024,表示超過多大時就不再年輕代分配,而是直接在老年代上分配。此參數在年輕代采用Parallel Scavenge GC時無效,因為其會根據運行情況自己決定什麽對象直接在老年代分配內存。另一種為大的數組對象,且數組對象中有引用外部對象。
當老年代滿了之後就需要對老年代進行垃圾回收,老年代的垃圾回收稱作Major GC(也稱作Full GC)。老年代所占用的內存大小為-Xmx 對應的值減去-Xmn對應的值。
4、JVM內存分配策略
對象的內存分配,在大方向上是在Java堆上進行內存分配。
大多數情況下,對象在新生代Eden區中分配,當Eden區沒有足夠空間分配時,虛擬機將發起一次Minor GC。
大多數情況下,大對象直接進入老年代,虛擬機提供了參數來定義大對象的閥值,超過閥值的直接進入老年代。
進過多次Minor GC仍然存活的對象將進入老年代,虛擬機提供了參數,可以設置閥值。
5、JVM常見啟動參數
- -Xmx 3550m:設置jvm最大堆內存為3550M。
- -Xms 3550:設置jvm初始堆內存為3550M。辭職可以設置成與Xmn一樣,以避免每次垃圾回收後jvm重新分配內存。
- -Xss 128k:設置每個線程的棧大小。JDK5.0以後每個線程大小為1M,之前每個線程棧大小為256K。應當根據應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,大概在3000-5000左右。需要註意的是:當這個值被設置的較大(例如>2M)時將會在很大程度上降低系統的性能。
- -Xmn 2G:設置年輕代大小為2G,在整個堆內存大小確定的情況下,增大年輕代將會減小年老代,反之亦然。此值關系得到JVM垃圾回收,對系統性能影響較大,官方推薦配置未整個堆大小的3/8。
- -XX:NewSize=1024m:設置年輕代初始值為1024M。
- -XX:MaxNewSize=1024:設置年輕代最大值為1024M。
- -XX:PermSize=256M:設置持久代初始值為256M。
- -XX:MaxPermSize=256M:設置持久代最大值為256M。
- -XX:NewRatio=4:設置年輕代(包括一個Eden和2個Survivor區)與老年代的比值,表示年輕代比年老代為1:4。
- -XX:SuvivorRatio=4:設置年輕代中的Eden區與Survivor區的比值,表示2個Survivor區與一個Eden區的比值為2:4,即一個Survivor區占整個年輕代內存大小的1/6。
疑問解答
-Xmn,-XX:NewSize/-XX:MaxNewSize,-XX:NewRatio 3組參數都可以影響年輕代的大小,混合使用情況下,優先級是什麽?
如下:
1.高優先級:-XX:NewSize/-XX:MaxNewSize
2.中優先級:-Xmn(默認等效-Xmn = -XX:NewSize = -XX:MaxNewSize =?)
3.低優先級:-XX:NewRatio
這三個參數推薦使用-Xmn,原因是這個參數簡潔,相當於一次設定-XX:NewSize與-XX:MaxNewSize,而且兩者相等,適用於生產環境,-Xmn配合-Xmx與-Xms,即可完成堆內存布局完成。
-Xmn參數是在JDK1.4開始支持。
JVM服務參數調優實戰
大型網站服務器按理
承受海量訪問的動態web應用
服務器配置:8 CPU,8G MEN,JDK1.6.x
參數方案:
-server -Xmx3550m -Xms3550m -Xmn1256m -Xss128k -XX:SurvivorRatio=6 -XX:MaxPermSize=256m -XX:ParallelGCThreads=8 -XX:MaxTenuringThreshold=0 -XX:+UseConcMarkSweepGC
調優說明:
- Xmx3550m -Xms3550m 相同避免每次垃圾回收後,jvm重新申請內存,-Xmx的大小約為系統內存的一半大小,充分利用了系統資源,又給予系統安全運行必要的內存空間。
- -Xmn設置為1256m,此值對系統性能影響比較大,Sun官方建議設置年輕代大小為整個堆的3/8,-Xmn/-Xmx約等於3/8。
- -Xss設置為128K,設置較小的線程棧,以支持創建更多的線程,支持海量訪問,並提高系統性能。
- -XX:SurvivorRatio設置為6,表示堆內存的年輕代中的2個Survivor區與Eden區的比值為2/6,一個Survivor區占整個年輕代內存大小的1/8。官方默認設置比值為8。
- -XX:ParallelGCThreads=8,表示配置並行收集器的個數為8個,即同時8個線程一起執行垃圾回收。此值一般設置成跟CPU數目相等。
高性能數據處理的工具應用
服務器配置:1 CPU, 4G MEM, JDK 1.6.X
參數方案:
-server -XX:PermSize=196m -XX:MaxPermSize=196m -Xmn320m -Xms768m -Xmx1024m
調優說明:
- -XX:PermSize=196m -XX:MaxPermSize=196m 大規模的系統編譯可能需要加載大量的java類到內存中,所以需要預先分配好大量的持久代內存是高效和必要的。
- -Xmn320m 等於-Xmn320m = -XX:NewSize = -XX:MaxNewSize = 320m;遵循年輕代大小為3/8
- -Xms768m -Xmx1024m根據系統大致配置能夠承受的堆內存大小設置即可。
6、JVM調優
查看堆內存空間大小(年輕代、老年代、持久代分配)
垃圾回收監控(長時間監控回收情況)
線程信息監控:系統線程數量
線程狀態監控:各個線程都處在什麽樣的狀態下
線程詳細信息監控:查看線程內部運行情況,死鎖檢查
CPU熱點:檢查系統哪些方法占用大量的CPU時間
內存熱點:檢查哪些對象在系統中數量最大
7、JAVA類的生命周期
java類從被加載到虛擬機中開始,知道卸載出內存為止,它的整個生命周期包括:加載、驗證、準備、解析、初始化、使用、卸載,七個階段。
8、性能優化的幾個方式
1、SQL優化(常用到)
2、java代碼優化
3、前端代碼優化
4、JVM優化
5、tomcat/jboss等中間件優化
sql優化
1、索引的優化
- 只要列中含有null值,就最好不要在此列設置索引
- 盡量使用短索引,如果可以,應該制定一個前綴長度
- 對應經常在where字句使用的列,最好設置索引,這樣會加快查找速度
- 盡量不要在列上進行運算(函數操作與表達式操作)
- 盡量不要使用not in和<>操作
2、SQL語句的優化
- 查詢時,能不要就不要寫,盡量寫全字段名
- 大部分情況連接效率遠大於子查詢
- 多表連接時,盡量小表驅動大表,即小表join大表(小表數據量小,循環查詢次數比大表的循環查詢次數少,查詢次數為表數據行數)
- 在千萬級分頁時使用limit
- 對於經常使用的查詢,可以開啟緩存
3、表的優化
- 表的字段盡可能用NOT NULL
- 字段長度固定的表查詢速度會更快
- 海量數據情況,大表按時間或按一定標誌分為小表
- 將表分區
java代碼優化
1、及時清除不再使用的對象,設為null
2、盡量使用原始類型和棧
Integer i = 888; //存儲在堆上
int i = 999; //存儲在棧上
//使用數組時情況可能會變得更糟糕
Integer[] i = {122,32342}; //在堆上生成3個對象
int[] i = {122,32342}; //僅在堆上生成一個對象
//應該極力避免使用包裝類,這樣做的壞處是創建了很多對象,給GC帶來非常大的壓力,GC將會為清楚包裝類生成的對象忙得不可開交。所以一個有效的優化方法是使用基本數據類型,定長數組,並用一系列分隔變量來標識對象在數組所處的位置
3、使用帶緩沖的輸入輸出流來進行IO操作,帶緩沖的輸出流:即 BufferedReader、BufferedWriter、BufferedInputStream,這可以極大的提升IO效率。
4、不要讓public方法中有太多的形參,形參多了可以考慮封裝一個實體類
5、使用數據庫連接池和線程池。這兩個池都是可重用對象的,前者可以避免頻繁的打開和關閉連接,後者可以避免頻繁的創建和銷毀線程。
6、乘法和除法使用移位操作
for(val = 0; val <10000;v ++){
a = val * 8;
b = val / 2;
}
//使用 移位操作可以極大提高新能,因為在計算機底層,對位的操作是最方便的最快的,因此建議修改為:
for(val = 0; val <10000;v ++){
a = val << 3;
b = val >> 1;
}
//左移一位乘2,右移一位除於2。移位操作雖然快,但是可能會使代碼不太好理解,最好加上相應的註釋
7、當復制大量數據時,使用System.arraycopy()方法。
8、盡量重用對象,特別是String對象的使用,由於java虛擬機不僅要花費時間來生成對象,以後還需要花費時間將這些對象進行垃圾回收和處理,因此生成過多的對象會對系統的性能造成很大的影響。
代碼優化的目標是:
1、減小代碼的體積
2、提高代碼的運行效率
前端優化
1、減少http請求次數,如將多個js文件合並成一個,這樣就只需要引用一個
2、文件壓縮,包括js、css、圖片資源等
3、緩存ajax,使用懶加載等技術
3、減少iframe數量
4、對圖片等資源可以考慮使用CDN技術、Gzip壓縮傳輸文件,避免空的圖片src
5、減少cookie大小
6、將腳本置底、使用外部js和css文件
7、減少DOM訪問
9、JAVA中常用的設計模式
1、單例模式
單例模式有以下幾個特點
- 單例類只能有一個實例
- 單例類必須自己創建自己的唯一實例
- 單例類必須給其他所有實例創建這一實例
// 1、懶漢示單例類,在第一次調用的時候實例化自己,這個方法需要將構造函數私有化,防止外部實例化這個類。不過懶漢式單例類線程不安全,並發環境下也許存在多個singleton的情況
public class Singleton{
private Singleton(){};
private static Singleton single = null;
//靜態工廠方法
public static Singleton getInstance(){
if(single == null){
single = new Singleton();
}
return single;
}
}
// 2、在getInstance()方法上加同步
public static synchronized Singleton getInstance(){
if(single == null){
single = new Singleton();
}
return single;
}
// 3、雙重檢查
public static Singleton getInstance(){
if(single == null){
synchronized(Singleton.class){
if(single == null){
single = new Singleton();
}
}
}
return single;
}
// 4、靜態內部類方式創建單例,這種方式既實現了線程安全,又避免了同步帶來的性能損失。java機制規定,內部類LazyHolder只有再第一次調用getInstance()方法時才會被加載,而且加載過程是線程安全的。
public class Singleton{
private static class LazyHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return LazyHolder.INSTANCE;
}
}
// 5、餓漢示,在類創建的同時就已經創建好了一個靜態的對象供給系統使用,以後不再改變,因此天生是線程安全的
public class Singleton{
private Singleton(){}
private static final Singleton single = new Singleton();
public static Singleton getInstance(){
return single;
}
}
2、工廠模式
工廠模式的兩種情況:
- 在編碼時不能預見需要創建哪些類的實例
- 系統不應該依賴於產品類實例如何被創建、組合和表達的細節
3、建造者模式
該模式其實就是說,一個對象的組成可能有很多其他的對象一起組成,比如說,一個對象的實現非常復雜,有很多屬性,而這些屬性又是其他對象的引用,可能這些對象的引用又包括很多其他對象的引用,封裝這些復雜性,就可以使用建造模式。
10、Collection集合
集合類繼承圖
Collection主要方法:
boolean add(Object o) 添加對象到集合
boolean remove(Object o) 刪除指定的對象
int size() 返回當前集合元素的數量
boolean contains(Object o) 查找集合內是否有指定的對象
boolean isEnpty() 判斷集合是否為空
Iterator iterator() 返回一個叠代器
boolean containsAll(Collection c) 查找集合內是否有集合c中的元素
boolean addAll(Collection c) 將集合c所有的元素添加給該集合
void clear() 刪除集合內所有的元素
void removeAll(Collection c) 從集合內刪除c集合也有的元素
void retainAll(Collection c) 從集合中刪除集合c中不包含的元素
List、主要子接口對象
list都是可重復有序的
||-LinkedList沒有同步方法
||-ArrayList非同步的
|-Vector(同步)非常類似ArrayList,但是它是同步的,這個是最大的區別,Vector類的大多數公開方法都用synchronized聲明過,所以是同步的
Set、不包含重復的元素
Map
map沒有繼承Collection接口,map提供key到value的映射
幾個主要的方法:
boolean equals(Object o) 比較對象
boolean remove(Object o) 刪除一個對象
put(Object key , Object value) 添加一個key和value
|-HashTable 任何非空( non-null ) 的對象。同步的
|-HashMap 可空的對象,不同步,但是效率高。
SortedMap —— TreeMap
總結:
a、如果涉及到堆棧,隊列(先進後出)等操作,應該考慮List,對於需要快速插入,刪除元素,應該使用LinkedList。如果需要快速隨機訪問元素,則使用ArrayList.
b、盡量返回接口而非實際的類型,如返回List而不是返回ArrayList,這樣如果以後需要將ArrayList換成LinkedList時,客戶端就不用改代碼,這就是針對接口編程。
幾個常見的面試問題
1、ArrayList和Vector有什麽區別?HashMap和HashTable有什麽區別?
答:Vector和HashTable是線程同步的,大部分的public方法都是synchronized修飾了的。性能上ArrayList和HashMap比較優秀。單線程或操作不影響數據的使用非同步的比較好。
2、大致講解java集合的體系結構
答:List、Set、Map是集合體系中最主要的三個接口。其中List和Set繼承自Collection接口。
Set不允許數據重復,HashSet和TreeSet是兩個主要的實現類
List有序且允許元素重復。ArrayList、LinkedList和Vector是三個主要的實現類
Map也屬於集合系統,但和Collection接口不通,map是key對value的映射集合,其中key列就是一個集合,key不能重復,但是value可以重復,hashMap、TreeMap、HashTable是三個主要的實現類。SortedSet和SortedMap接口對元素按指定規則排序,SortedMap是對key列進行排序。
3、為什麽集合類沒有實現Cloneable和Serializable接口?
答:因為接口類指定了一組叫元素的對象,集合類接口的每一種具體的實現類都可以選擇它自己的方式對元素進行保存和排序,有的集合允許重復的鍵,有些不允許。克隆或者是序列化的語義和含義是跟具體的實現相關的,因此應該由集合類的具體實現來決定如何被克隆或者是序列化。
4、什麽是叠代器(Iterator)
答:Iterator接口提供了很多對集合元素進行叠代的方法,每一個集合類都包含了可以返回叠代器實例的叠代方法,叠代器可以在叠代的過程中刪除底層集合的元素,安全。Iterator叠代器是工廠模式設計的,不同的集合返回對應的實例。
5、快速失敗(fail-fast)和安全失敗(fail-safe)的區別是什麽?
Iterator的安全失敗是基於對底層集合做拷貝,因此,它不受源集合上修改的影響,java.util包下面的所有的集合類都是快速失敗的,而java.util.concurrent包下面的所有類都是安全失敗的。快速失敗的叠代器會拋出ConcurrentModificationException異常,而安全失敗的叠代器則不會拋出這樣的異常。
6、hashMap的工作原理是什麽
java中的hashMap是以鍵值對的形式存儲元素的。hashmap需要一個hash函數,它使用hashCode()和equals()方法來向集合或從集合添加和檢索元素。
當調用put()方法的時候,hashMap會計算key的hash值,然後把鍵值對存儲在集合中合適的索引位置上。如果key已經存在,value值會被更新成新值,get()方法同理。
7、hashCode()和equals()方法的重要性體現在什麽地方?
java中的hashMap通過hashCode()和equals()方法來確定鍵值對的索引,當用put()或get()方法時,如果沒有正確的實現這兩個方法,兩個不同的鍵值對可能會有相同的hash值,因此可能會被集合認為是相等的。而且,這兩個方法也用來發現重復元素,所以這兩個方法的實現對hashMap的精確性和正確性相當重要。
8、ArrayList和LinkedList有什麽區別?
兩者都實現List接口,他們有以下不同點:
數據結構上:
ArrayList是基於索引的數組形式,可隨機訪問
LinkedList是元素列表的形式存儲它的數據,每一個元素都和他的前一個和後一個元素鏈接在一起
操作上:
ArrayList添加、刪除操作比較慢,需要重新計算大小或者更新索引
LinkedList的插入、刪除操作比較快,不需要更新索引
內存上:
LinkedList更占用內存,因為每個LinkedList為每個節點存儲了兩個引用,一個指向前一個元素,一個指向後一個元素
9、集合類跟數組array的區別
數組特點:大小固定,只能存儲相同類型的數據
集合特點:大小可動態擴展,可以存儲不同類型的數據
轉換:
將數組轉換為集合:Arrays.asList(數組); 這裏註意當數組元素是數字時需要將數字封裝成包裝類才能轉換
將集合轉換為數組:集合.toArray();
示例:
//數組轉換成集合
int[] arr = {1,2,3,4,5};
int size = arr.length;
Integer[] integers = new Integer[size];
for (int i = 0;i<size;i++){
Integer ii = arr[i];
integers[i] = ii;
}
List list = Arrays.asList(integers);
//集合轉換成數組
List list = new ArrayList();
list.add("a");
list.add("b");
String[] strs = list.toArray();
遍歷map的方式
a、最常規的一種遍歷方法,最常規也就是最常用的,雖不復雜但是很重要
public static void work(Map<String, Student> map) {
Collection c = map.values();
Iterator it = c.iterator();
for(;it.hasNext();){
System.out.println(it.next());
}
}
b、根據keySet進行遍歷,它的有點在於可以根據你所想要的key值得到你想要的values,更具靈活性
public static void workByKeySet(Map<String, Student> map) {
Set keys = map.keySet();
for(Iterator i = keys.iterator();i.hasNext();){
String key = (String)i.next();
System.out.println(map.get(key));
}
}
c、比較復雜的一種遍歷在這裏,暴力,它的靈活性太強了。想得到什麽就能得到什麽,這種效率比較高
public static void workByEntry(Map<String, Student> map) {
Set<Map.Enter<String, Student>> set = map.entrySet();
for (Map.Entry<String, Student> me : set) {
System.out.println(me.getKey() + "—>" + me.getValue());
}
}
11、java異常分類和常見的幾個異常
- Error
- Runtime Exception運行時異常
- Exception
- throw 用戶自定義異常
異常類分為兩大類型:
1、Error類代表編譯和系統的錯誤,不允許捕獲;
2、Exception代表標準的java庫激發出的異常,Exception包含運行時異常和非運行時異常兩個直接的子類
運行時異常對應於編譯錯誤,它是指java程序在運行時產生的由解釋器引發的各種異常。異常可能出現在任何地方,且出現頻率很高,因此為了避免巨大的系統資源開銷,編譯器不對運行時異常進行檢查,所以java語言中的運行異常不一定被捕獲,出現運行錯誤往往表示代碼有錯誤,如:算數異常(如被0除)、下標異常(如數組下標越界)等。
非運行異常時Non_RuntimeException類及其子類的實例,又稱為可檢測異常。Java編譯器利用分析方法或構造方法中可能產生的結果來檢測Java程序中是否含有檢測異常的處理程序,對於每個可能的可檢測異常,方法或構造方法的throws子句必須列出該異常對應的類。在Java的標準包java.lang java.util 和 java.net 中定義的異常都是非運行異常。
常見異常:
空指針異常類:NullPointerException
類型強制轉換異常:ClassCastException
文件已結束異常:EOFException
字符串轉換為數字異常:NumberFormatException
操作數據庫異常:SQLException
輸入輸出異常:IOException
方法未找到異常:NoSuchMethodException
java.lang.IllegalAccessError:違法訪問錯誤。當一個應用試圖訪問、修改某個類的域(Field)或者調用其方法,但是又違反域或方法的可見性聲明,則拋出該異常。
java.lang.NoClassDefFoundError
未找到類定義錯誤。當Java虛擬機或者類裝載器試圖實例化某個類,而找不到該類的定義時拋出該錯誤。
java.lang.OutOfMemoryError
內存不足錯誤。當可用內存不足以讓Java虛擬機分配給一個對象時拋出該錯誤。
java.lang.StackOverflowError
堆棧溢出錯誤。當一個應用遞歸調用的層次太深而導致堆棧溢出時拋出該錯誤。
12、jvm運行機制
1、java源碼使用javac編譯成*.class文件(字節碼文件)
2、類加載
3、類執行
java面試筆記