Java的面試基礎(chǔ)題(二)

集合框架:

1)特點(diǎn):存儲(chǔ)對象杉允;長度可變署鸡;存儲(chǔ)對象的類型可不同
2)Collection
(1)List:有序的;元素可重復(fù),有索引
(add(index, element)骑科、add(index, Collection)、remove(index)构拳、set(index,element)咆爽、get(index)、subList(from, to)置森、listIterator())
①ArrayList:底層是數(shù)組結(jié)構(gòu)斗埂,查詢快,增刪慢凫海,不同步呛凶。
②LinkedList:底層是鏈表結(jié)構(gòu),增刪快行贪,查詢慢漾稀,不同步
addFist();addLast() getFirst();getLast()
removeFirst();removeLast() 獲取并刪除元素,無元素將拋異常:NoSuchElementException
替代的方法(JDK1.6):
offerFirst();offerLast();
peekFirst();peekLast();無元素返回null
pollFirst();pollLast();刪除并返回此元素建瘫,無元素返回null
③Vector:底層是數(shù)組結(jié)構(gòu)崭捍,線程同步,被ArrayList取代了
注:了對于判斷是否存在啰脚,以及刪除等操作殷蛇,以依賴的方法是元素的hashCode和equals方法
ArrayList判斷是否存在和刪除操作依賴的是equals方法

(2)Set:無序的,無索引橄浓,元素不可重復(fù)
①HashSet:底層是哈希表粒梦,線程不同步,無序荸实、高效
保證元素唯一性:通過元素的hashCode和equals方法匀们。若hashCode值相同,則會(huì)判斷equals的結(jié)果是否為true泪勒;hashCode不同昼蛀,不會(huì)調(diào)用equals方法
LinkedHashSet:有序宴猾,是HashSet的子類
②TreeSet:底層是二叉樹圆存,可對元素進(jìn)行排序叼旋,默認(rèn)是自然順序
保證唯一性:Comparable接口的compareTo方法的返回值
===》TreeSet兩種排序方式:兩種方式都存在時(shí),以比較器為主
第一種:自然排序(默認(rèn)排序):
添加的對象需要實(shí)現(xiàn)Comparable接口沦辙,覆蓋compareTo方法
第二種:比較器
添加的元素自身不具備比較性或不是想要的比較方式夫植。將比較器作為參數(shù)傳遞進(jìn)去。
定義一個(gè)類油讯,實(shí)現(xiàn)Comparator接口详民,覆蓋compare方法。當(dāng)主要條件相同時(shí)陌兑,比較次要條件沈跨。

3)Map集合:
(1)HashTable:底層數(shù)據(jù)結(jié)構(gòu)是哈希表,不可存入null鍵和null值兔综。同步的
Properties繼承自HashTable饿凛,可保存在流中或從流中加載,是集合和IO流的結(jié)合產(chǎn)物
(2)HashMap:底層數(shù)據(jù)結(jié)構(gòu)是哈希表软驰;允許使用null鍵和null值涧窒,不同步,效率高
TreeMap:
底層數(shù)據(jù)結(jié)構(gòu)時(shí)二叉樹锭亏,不同步纠吴,可排序
與Set很像,Set底層就是使用了Map集合
方法:
V put(K key, V value) ; void putAll(Map m)
void clear(); V remove(Object key)
boolean containsKey(Object key); containsValue(Object key); isEmpty()
V get(Object key); int size(); Collection<V> values()
Set<K> keySet(); Set<Map.Entry<K,V>> entrySet()

2.3慧瘤、Map集合兩種取出方式:
第一種:Set<K> keySet()
取出Map集合中的所有鍵放于Set集合中戴已,然后再通過鍵取出對應(yīng)的值
Set<String> keySet = map.keySet();
Iterator<String> it = keySet.iterator();
while(it.hasNext()){
String key = it.next();
String value = map.get(key);
//…..
}
第二種:Set<Map.Entry<K,V>> entrySet()
取出Map集合中鍵值對的映射放于Set集合中,然后通過Map集合中的內(nèi)部接口锅减,然后通過其中的方法取出
Set<Map.Entry<String,String>> entrySet = map.entrySet();
Iterator<Map.Entry<String,String>> it = entrySet.iterator();
While(it.hasNext()){
Map.Entry<String,String> entry = it.next();
String key = entry.getKey();
String value = entry.getValue();
//……
}

2.4恭陡、Collection和Map的區(qū)別:
Collection:單列集合,一次存一個(gè)元素
Map:雙列集合上煤,一次存一對集合休玩,兩個(gè)元素(對象)存在著映射關(guān)系

2.5、集合工具類:
Collections:操作集合(一般是list集合)的工具類劫狠。方法全為靜態(tài)的
sort(List list);對list集合進(jìn)行排序; sort(List list, Comparator c) 按指定比較器排序
fill(List list, T obj);將集合元素替換為指定對象拴疤;
swap(List list, int I, int j)交換集合指定位置的元素
shuffle(List list); 隨機(jī)對集合元素排序
reverseOrder() :返回比較器,強(qiáng)行逆轉(zhuǎn)實(shí)現(xiàn)Comparable接口的對象自然順序
reverseOrder(Comparator c):返回比較器独泞,強(qiáng)行逆轉(zhuǎn)指定比較器的順序

2.6呐矾、Collection和Collections的區(qū)別:
Collections:java.util下的工具類,實(shí)現(xiàn)對集合的查找懦砂、排序蜒犯、替換组橄、線程安全化等操作。
Collection:是java.util下的接口罚随,是各種單列集合的父接口玉工,實(shí)現(xiàn)此接口的有List和Set集合,存儲(chǔ)對象并對其進(jìn)行操作淘菩。

3遵班、Arrays:
用于操作數(shù)組對象的工具類,全為靜態(tài)方法
asList():將數(shù)組轉(zhuǎn)為list集合
好處:可通過list集合的方法操作數(shù)組中的元素:
isEmpty()潮改、contains()狭郑、indexOf()、set()
弊端:數(shù)組長度固定汇在,不可使用集合的增刪操作翰萨。
如果數(shù)組中存儲(chǔ)的是基本數(shù)據(jù)類型,asList會(huì)將數(shù)組整體作為一個(gè)元素存入集合
集合轉(zhuǎn)為數(shù)組:Collection.toArray()糕殉;
好處:限定了對集合中的元素進(jìn)行增刪操作亩鬼,只需獲取元素

進(jìn)程和線程的區(qū)別

簡而言之,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程。

線程的劃分尺度小于進(jìn)程糙麦,使得多線程程序的并發(fā)性高辛孵。

另外,進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元赡磅,而多個(gè)線程共享內(nèi)存魄缚,從而極大地提高了程序的運(yùn)行效率。

線程在執(zhí)行過程中與進(jìn)程還是有區(qū)別的焚廊。每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口冶匹、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行咆瘟,必須依存在應(yīng)用程序中嚼隘,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。

從邏輯角度來看袒餐,多線程的意義在于一個(gè)應(yīng)用程序中飞蛹,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒有將多個(gè)線程看做多個(gè)獨(dú)立的應(yīng)用灸眼,來實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配卧檐。這就是進(jìn)程和線程的重要區(qū)別。

進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.

線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.

一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程;同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行.

進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式焰宣。進(jìn)程有獨(dú)立的地址空間霉囚,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對其它進(jìn)程產(chǎn)生影響匕积,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑盈罐。線程有自己的堆棧和局部變量榜跌,但線程之間沒有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉盅粪,所以多進(jìn)程的程序要比多線程的程序健壯钓葫,但在進(jìn)程切換時(shí),耗費(fèi)資源較大湾揽,效率要差一些瓤逼。但對于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作笼吟,只能用線程库物,不能用進(jìn)程。如果有興趣深入的話贷帮,我建議你們看看《現(xiàn)代操作系統(tǒng)》或者《操作系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)》戚揭。對就個(gè)問題說得比較清楚。

內(nèi)部類的作用內(nèi)部類可以用多個(gè)實(shí)例撵枢,每個(gè)實(shí)例都有自己的狀態(tài)信息民晒,并且-
  • 與其他外圍對象的信息相互獨(dú)立。
  • 在單個(gè)外圍類中锄禽,可以讓多個(gè)內(nèi)部類以不同的方式實(shí)現(xiàn)同一個(gè)接口潜必,或者繼承同一個(gè)類。
  • 創(chuàng)建內(nèi)部類對象的時(shí)刻并不依賴于外圍類對象的創(chuàng)建沃但。
  • 內(nèi)部類并沒有令人迷惑的“is-a”關(guān)系磁滚,他就是一個(gè)獨(dú)立的實(shí)體。
  • 內(nèi)部類提供了更好的封裝宵晚,除了該外圍類垂攘,其他類都不能訪問
哪些情況下的對象會(huì)被垃圾回收機(jī)制處理掉

Java 垃圾回收機(jī)制最基本的做法是分代回收。內(nèi)存中的區(qū)域被劃分成不同的世代淤刃,對象根據(jù)其存活的時(shí)間被保存在對應(yīng)世代的區(qū)域中晒他。一般的實(shí)現(xiàn)是劃分成3個(gè)世代:年輕、年老和永久逸贾。內(nèi)存的分配是發(fā)生在年輕世代中的陨仅。當(dāng)一個(gè)對象存活時(shí)間足夠長的時(shí)候,它就會(huì)被復(fù)制到年老世代中铝侵。對于不同的世代可以使用不同的垃圾回收算法灼伤。進(jìn)行世代劃分的出發(fā)點(diǎn)是對應(yīng)用中對象存活時(shí)間進(jìn)行研究之后得出的統(tǒng)計(jì)規(guī)律。一般來說哟沫,一個(gè)應(yīng)用中的大部分對象的存活時(shí)間都很短饺蔑。比如局部變量的存活時(shí)間就只在方法的執(zhí)行過程中∈染鳎基于這一點(diǎn)猾警,對于年輕世代的垃圾回收算法就可以很有針對性孔祸。

進(jìn)程和線程的區(qū)別

簡而言之,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程。
線程的劃分尺度小于進(jìn)程发皿,使得多線程程序的并發(fā)性高崔慧。
另外,進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元穴墅,而多個(gè)線程共享內(nèi)存惶室,從而極大地提高了程序的運(yùn)行效率。
線程在執(zhí)行過程中與進(jìn)程還是有區(qū)別的玄货。每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口皇钞、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行松捉,必須依存在應(yīng)用程序中夹界,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。
從邏輯角度來看隘世,多線程的意義在于一個(gè)應(yīng)用程序中可柿,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒有將多個(gè)線程看做多個(gè)獨(dú)立的應(yīng)用丙者,來實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配复斥。這就是進(jìn)程和線程的重要區(qū)別。
進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.
線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.
一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程;同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行.
進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式械媒。進(jìn)程有獨(dú)立的地址空間目锭,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對其它進(jìn)程產(chǎn)生影響滥沫,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑侣集。線程有自己的堆棧和局部變量,但線程之間沒有單獨(dú)的地址空間兰绣,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉世分,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時(shí)缀辩,耗費(fèi)資源較大臭埋,效率要差一些。但對于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作臀玄,只能用線程瓢阴,不能用進(jìn)程。如果有興趣深入的話健无,我建議你們看看《現(xiàn)代操作系統(tǒng)》或者《操作系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)》荣恐。對就個(gè)問題說得比較清楚。

Java中==和equals的區(qū)別,equals和hashCode的區(qū)別

==是運(yùn)算符叠穆,用于比較兩個(gè)變量是否相等少漆。
equals,是Objec類的方法硼被,用于比較兩個(gè)對象是否相等示损,默認(rèn)Object類的equals方法是比較兩個(gè)對象的地址,跟==的結(jié)果一樣嚷硫。
hashCode也是Object類的一個(gè)方法检访。返回一個(gè)離散的int型整數(shù)。在集合類操作中使用仔掸,為了提高查詢速度脆贵。(HashMap,HashSet等)
1.基本數(shù)據(jù)類型嘉汰,也稱原始數(shù)據(jù)類型丹禀。byte,short,char,int,long,float,double,boolean
他們之間的比較状勤,應(yīng)用雙等號(hào)(==),比較的是他們的值鞋怀。
2.復(fù)合數(shù)據(jù)類型(類)
當(dāng)他們用(==)進(jìn)行比較的時(shí)候,比較的是他們在內(nèi)存中的存放地址持搜,所以密似,除非是同一個(gè)new出來的對象,他們的比較后的結(jié)果為true葫盼,否則比較后結(jié)果為false残腌。 JAVA當(dāng)中所有的類都是繼承于Object這個(gè)基類的,在Object中的基類中定義了一個(gè)equals的方法贫导,這個(gè)方法的初始行為是比較對象的內(nèi)存地 址抛猫,但在一些類庫當(dāng)中這個(gè)方法被覆蓋掉了,如String,Integer,Date在這些類當(dāng)中equals有其自身的實(shí)現(xiàn)孩灯,而不再是比較類在堆內(nèi)存中的存放地址了闺金。
對于復(fù)合數(shù)據(jù)類型之間進(jìn)行equals比較,在沒有覆寫equals方法的情況下峰档,他們之間的比較還是基于他們在內(nèi)存中的存放位置的地址值的败匹,因?yàn)镺bject的equals方法也是用雙等號(hào)(==)進(jìn)行比較的,所以比較后的結(jié)果跟雙等號(hào)(==)的結(jié)果相同讥巡。
如果兩個(gè)對象根據(jù)equals()方法比較是相等的掀亩,那么調(diào)用這兩個(gè)對象中任意一個(gè)對象的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果。
如果兩個(gè)對象根據(jù)equals()方法比較是不相等的欢顷,那么調(diào)用這兩個(gè)對象中任意一個(gè)對象的hashCode方法槽棍,則不一定要產(chǎn)生相同的整數(shù)結(jié)果
從而在集合操作的時(shí)候有如下規(guī)則:
將對象放入到集合中時(shí),首先判斷要放入對象的hashcode值與集合中的任意一個(gè)元素的hashcode值是否相等,如果不相等直接將該對象放入集合中炼七。如果hashcode值相等外里,然后再通過equals方法判斷要放入對象與集合中的任意一個(gè)對象是否相等,如果equals判斷不相等特石,直接將該元素放入到集合中盅蝗,否則不放入。
回過來說get的時(shí)候姆蘸,HashMap也先調(diào)key.hashCode()算出數(shù)組下標(biāo)墩莫,然后看equals如果是true就是找到了,所以就涉及了equals逞敷。

HashMap的實(shí)現(xiàn)原理

HashMap概述: HashMap是基于哈希表的Map接口的非同步實(shí)現(xiàn)狂秦。此實(shí)現(xiàn)提供所有可選的映射操作,并允許使用null值和null鍵推捐。此類不保證映射的順序裂问,特別是它不保證該順序恒久不變。
HashMap的數(shù)據(jù)結(jié)構(gòu): 在java編程語言中牛柒,最基本的結(jié)構(gòu)就是兩種堪簿,一個(gè)是數(shù)組,另外一個(gè)是模擬指針(引用)皮壁,所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個(gè)基本結(jié)構(gòu)來構(gòu)造的椭更,HashMap也不例外。HashMap實(shí)際上是一個(gè)“鏈表散列”的數(shù)據(jù)結(jié)構(gòu)蛾魄,即數(shù)組和鏈表的結(jié)合體虑瀑。

string stringbuffer stringbuilder 區(qū)別

String 字符串常量
StringBuffer 字符串變量(線程安全)
StringBuilder 字符串變量(非線程安全)
簡要的說, String 類型和 StringBuffer 類型的主要性能區(qū)別其實(shí)在于 String 是不可變的對象, 因此在每次對 String 類型進(jìn)行改變的時(shí)候其實(shí)都等同于生成了一個(gè)新的 String 對象滴须,然后將指針指向新的 String 對象舌狗,所以經(jīng)常改變內(nèi)容的字符串最好不要用String ,因?yàn)槊看紊蓪ο蠖紩?huì)對系統(tǒng)性能產(chǎn)生影響扔水,特別當(dāng)內(nèi)存中無引用對象多了以后,JVM 的 GC 就會(huì)開始工作痛侍,那速度是一定會(huì)相當(dāng)慢的。
而如果是使用 StringBuffer 類則結(jié)果就不一樣了铭污,每次結(jié)果都會(huì)對 StringBuffer 對象本身進(jìn)行操作恋日,而不是生成新的對象,再改變對象引用嘹狞。所以在一般情況下我們推薦使用 StringBuffer 岂膳,特別是字符串對象經(jīng)常改變的情況下。而在某些特別情況下磅网, String 對象的字符串拼接其實(shí)是被 JVM 解釋成了 StringBuffer 對象的拼接谈截,所以這些時(shí)候 String 對象的速度并不會(huì)比 StringBuffer 對象慢,而特別是以下的字符串對象生成中, String 效率是遠(yuǎn)要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”); 你會(huì)很驚訝的發(fā)現(xiàn)簸喂,生成 String S1 對象的速度簡直太快了毙死,而這個(gè)時(shí)候 StringBuffer 居然速度上根本一點(diǎn)都不占優(yōu)勢。其實(shí)這是 JVM 的一個(gè)把戲喻鳄,在 JVM 眼里扼倘,這個(gè) String S1 = “This is only a” + “ simple” + “test”; 其實(shí)就是: String S1 = “This is only a simple test”; 所以當(dāng)然不需要太多的時(shí)間了。但大家這里要注意的是除呵,如果你的字符串是來自另外的 String 對象的話再菊,速度就沒那么快了,譬如: String S2 = “This is only a”; String S3 = “ simple”; String S4 = “ test”; String S1 = S2 +S3 + S4; 這時(shí)候 JVM 會(huì)規(guī)規(guī)矩矩的按照原來的方式去做
在大部分情況下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer線程安全的可變字符序列颜曾。一個(gè)類似于 String 的字符串緩沖區(qū)纠拔,但不能修改。雖然在任意時(shí)間點(diǎn)上它都包含某種特定的字符序列泛豪,但通過某些方法調(diào)用可以改變該序列的長度和內(nèi)容稠诲。
可將字符串緩沖區(qū)安全地用于多個(gè)線程」钍铮可以在必要時(shí)對這些方法進(jìn)行同步臀叙,因此任意特定實(shí)例上的所有操作就好像是以串行順序發(fā)生的,該順序與所涉及的每個(gè)線程進(jìn)行的方法調(diào)用順序一致岗仑。
StringBuffer 上的主要操作是 append 和 insert 方法匹耕,可重載這些方法,以接受任意類型的數(shù)據(jù)荠雕。每個(gè)方法都能有效地將給定的數(shù)據(jù)轉(zhuǎn)換成字符串,然后將該字符串的字符追加或插入到字符串緩沖區(qū)中驶赏。append 方法始終將這些字符添加到緩沖區(qū)的末端炸卑;而 insert 方法則在指定的點(diǎn)添加字符。
例如煤傍,如果 z 引用一個(gè)當(dāng)前內(nèi)容是“start”的字符串緩沖區(qū)對象盖文,則此方法調(diào)用 z.append("le") 會(huì)使字符串緩沖區(qū)包含“startle”,而 z.insert(4, "le") 將更改字符串緩沖區(qū)蚯姆,使之包含“starlet”五续。
在大部分情況下 StringBuilder > StringBuffer
java.lang.StringBuilder
java.lang.StringBuilder一個(gè)可變的字符序列是5.0新增的。此類提供一個(gè)與 StringBuffer 兼容的 API龄恋,但不保證同步疙驾。該類被設(shè)計(jì)用作 StringBuffer 的一個(gè)簡易替換,用在字符串緩沖區(qū)被單個(gè)線程使用的時(shí)候(這種情況很普遍)郭毕。如果可能它碎,建議優(yōu)先采用該類,因?yàn)樵诖蠖鄶?shù)實(shí)現(xiàn)中,它比 StringBuffer 要快扳肛。兩者的方法基本相同

什么導(dǎo)致線程阻塞

線程的阻塞

為了解決對共享存儲(chǔ)區(qū)的訪問沖突傻挂,Java 引入了同步機(jī)制,現(xiàn)在讓我們來考察多個(gè)線程對共享資源的訪問挖息,顯然同步機(jī)制已經(jīng)不夠了金拒,因?yàn)樵谌我鈺r(shí)刻所要求的資源不一定已經(jīng)準(zhǔn)備好了被訪問,反過來套腹,同一時(shí)刻準(zhǔn)備好了的資源也可能不止一個(gè)殖蚕。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機(jī)制的支持.

阻塞指的是暫停一個(gè)線程的執(zhí)行以等待某個(gè)條件發(fā)生(如某資源就緒)沉迹,學(xué)過操作系統(tǒng)的同學(xué)對它一定已經(jīng)很熟悉了睦疫。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析鞭呕。

sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時(shí)間作為參數(shù)蛤育,它使得線程在指定的時(shí)間內(nèi)進(jìn)入阻塞狀態(tài),不能得到CPU 時(shí)間葫松,指定的時(shí)間一過瓦糕,線程重新進(jìn)入可執(zhí)行狀態(tài)。 典型地腋么,sleep() 被用在等待某個(gè)資源就緒的情形:測試發(fā)現(xiàn)條件不滿足后咕娄,讓線程阻塞一段時(shí)間后重新測試,直到條件滿足為止珊擂。
suspend() 和 resume() 方法:兩個(gè)方法配套使用圣勒,suspend()使得線程進(jìn)入阻塞狀態(tài),并且不會(huì)自動(dòng)恢復(fù)摧扇,必須其對應(yīng)的resume() 被調(diào)用圣贸,才能使得線程重新進(jìn)入可執(zhí)行狀態(tài)。典型地扛稽,suspend() 和 resume() 被用在等待另一個(gè)線程產(chǎn)生的結(jié)果的情形:測試發(fā)現(xiàn)結(jié)果還沒有產(chǎn)生后吁峻,讓線程阻塞,另一個(gè)線程產(chǎn)生了結(jié)果后在张,調(diào)用 resume() 使其恢復(fù)用含。
yield() 方法:yield() 使得線程放棄當(dāng)前分得的 CPU 時(shí)間,但是不使線程阻塞帮匾,即線程仍處于可執(zhí)行狀態(tài)啄骇,隨時(shí)可能再次分得 CPU 時(shí)間。調(diào)用 yield() 的效果等價(jià)于調(diào)度程序認(rèn)為該線程已執(zhí)行了足夠的時(shí)間從而轉(zhuǎn)到另一個(gè)線程.
wait() 和 notify() 方法:兩個(gè)方法配套使用辟狈,wait() 使得線程進(jìn)入阻塞狀態(tài)肠缔,它有兩種形式夏跷,一種允許 指定以毫秒為單位的一段時(shí)間作為參數(shù),另一種沒有參數(shù)明未,前者當(dāng)對應(yīng)的 notify() 被調(diào)用或者超出指定時(shí)間時(shí)線程重新進(jìn)入可執(zhí)行狀態(tài)槽华,后者則必須對應(yīng)的 notify() 被調(diào)用.
初看起來它們與 suspend() 和 resume() 方法對沒有什么分別,但是事實(shí)上它們是截然不同的趟妥。區(qū)別的核心在于猫态,前面敘述的所有方法,阻塞時(shí)都不會(huì)釋放占用的鎖(如果占用了的話)披摄,而這一對方法則相反亲雪。

上述的核心區(qū)別導(dǎo)致了一系列的細(xì)節(jié)上的區(qū)別。

首先疚膊,前面敘述的所有方法都隸屬于 Thread 類义辕,但是這一對卻直接隸屬于 Object 類,也就是說寓盗,所有對象都擁有這一對方法灌砖。初看起來這十分不可思議,但是實(shí)際上卻是很自然的傀蚌,因?yàn)檫@一對方法阻塞時(shí)要釋放占用的鎖基显,而鎖是任何對象都具有的,調(diào)用任意對象的 wait() 方法導(dǎo)致線程阻塞善炫,并且該對象上的鎖被釋放撩幽。而調(diào)用 任意對象的notify()方法則導(dǎo)致因調(diào)用該對象的 wait() 方法而阻塞的線程中隨機(jī)選擇的一個(gè)解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)。

其次箩艺,前面敘述的所有方法都可在任何位置調(diào)用窜醉,但是這一對方法卻必須在 synchronized 方法或塊中調(diào)用,理由也很簡單舅桩,只有在synchronized 方法或塊中當(dāng)前線程才占有鎖酱虎,才有鎖可以釋放。同樣的道理,調(diào)用這一對方法的對象上的鎖必須為當(dāng)前線程所擁有珊肃,這樣才有鎖可以釋放坝撑。因此,這一對方法調(diào)用必須放置在這樣的 synchronized 方法或塊中忆绰,該方法或塊的上鎖對象就是調(diào)用這一對方法的對象。若不滿足這一條件,則程序雖然仍能編譯狰右,但在運(yùn)行時(shí)會(huì)出現(xiàn)IllegalMonitorStateException 異常。

wait() 和 notify() 方法的上述特性決定了它們經(jīng)常和synchronized 方法或塊一起使用舆床,將它們和操作系統(tǒng)的進(jìn)程間通信機(jī)制作一個(gè)比較就會(huì)發(fā)現(xiàn)它們的相似性:synchronized方法或塊提供了類似于操作系統(tǒng)原語的功能棋蚌,它們的執(zhí)行不會(huì)受到多線程機(jī)制的干擾嫁佳,而這一對方法則相當(dāng)于 block 和wakeup 原語(這一對方法均聲明為 synchronized)。它們的結(jié)合使得我們可以實(shí)現(xiàn)操作系統(tǒng)上一系列精妙的進(jìn)程間通信的算法(如信號(hào)量算法)谷暮,并用于解決各種復(fù)雜的線程間通信問題蒿往。

關(guān)于 wait() 和 notify() 方法最后再說明兩點(diǎn):

第一:調(diào)用 notify() 方法導(dǎo)致解除阻塞的線程是從因調(diào)用該對象的 wait() 方法而阻塞的線程中隨機(jī)選取的,我們無法預(yù)料哪一個(gè)線程將會(huì)被選擇湿弦,所以編程時(shí)要特別小心瓤漏,避免因這種不確定性而產(chǎn)生問題。

第二:除了 notify()颊埃,還有一個(gè)方法 notifyAll() 也可起到類似作用蔬充,唯一的區(qū)別在于,調(diào)用 notifyAll() 方法將把因調(diào)用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞班利。當(dāng)然饥漫,只有獲得鎖的那一個(gè)線程才能進(jìn)入可執(zhí)行狀態(tài)。

談到阻塞罗标,就不能不談一談死鎖庸队,略一分析就能發(fā)現(xiàn),suspend() 方法和不指定超時(shí)期限的 wait() 方法的調(diào)用都可能產(chǎn)生死鎖馒稍。遺憾的是皿哨,Java 并不在語言級別上支持死鎖的避免,我們在編程中必須小心地避免死鎖纽谒。

以上我們對 Java 中實(shí)現(xiàn)線程阻塞的各種方法作了一番分析证膨,我們重點(diǎn)分析了 wait() 和 notify() 方法,因?yàn)樗鼈兊墓δ茏顝?qiáng)大鼓黔,使用也最靈活央勒,但是這也導(dǎo)致了它們的效率較低,較容易出錯(cuò)澳化。實(shí)際使用中我們應(yīng)該靈活使用各種方法崔步,以便更好地達(dá)到我們的目的。

Thread類的sleep()方法和對象的wait()方法都可以讓線程暫停執(zhí)行缎谷,它們有什么區(qū)別?

答:sleep()方法(休眠)是線程類(Thread)的靜態(tài)方法井濒,調(diào)用此方法會(huì)讓當(dāng)前線程暫停執(zhí)行指定的時(shí)間,將執(zhí)行機(jī)會(huì)(CPU)讓給其他線程列林,但是對象的鎖依然保持瑞你,因此休眠時(shí)間結(jié)束后會(huì)自動(dòng)恢復(fù)(線程回到就緒狀態(tài),請參考第66題中的線程狀態(tài)轉(zhuǎn)換圖)希痴。wait()是Object類的方法者甲,調(diào)用對象的wait()方法導(dǎo)致當(dāng)前線程放棄對象的鎖(線程暫停執(zhí)行),進(jìn)入對象的等待池(wait pool)砌创,只有調(diào)用對象的notify()方法(或notifyAll()方法)時(shí)才能喚醒等待池中的線程進(jìn)入等鎖池(lock pool)虏缸,如果線程重新獲得對象的鎖就可以進(jìn)入就緒狀態(tài)鲫懒。

面向?qū)ο蟮奶卣饔心男┓矫妫?/h5>

答:面向?qū)ο蟮奶卣髦饕幸韵聨讉€(gè)方面:

  • 抽象:抽象是將一類對象的共同特征總結(jié)出來構(gòu)造類的過程,包括數(shù)據(jù)抽象和行為抽象兩方面刽辙。抽象只關(guān)注對象有哪些屬性和行為窥岩,并不關(guān)注這些行為的細(xì)節(jié)是什么。
  • 繼承:繼承是從已有類得到繼承信息創(chuàng)建新類的過程扫倡。提供繼承信息的類被稱為父類(超類谦秧、基類);得到繼承信息的類被稱為子類(派生類)撵溃。繼承讓變化中的軟件系統(tǒng)有了一定的延續(xù)性疚鲤,同時(shí)繼承也是封裝程序中可變因素的重要手段(如果不能理解請閱讀閻宏博士的《Java與模式》或《設(shè)計(jì)模式精解》中關(guān)于橋梁模式的部分)。
  • 封裝:通常認(rèn)為封裝是把數(shù)據(jù)和操作數(shù)據(jù)的方法綁定起來缘挑,對數(shù)據(jù)的訪問只能通過已定義的接口集歇。面向?qū)ο蟮谋举|(zhì)就是將現(xiàn)實(shí)世界描繪成一系列完全自治、封閉的對象语淘。我們在類中編寫的方法就是對實(shí)現(xiàn)細(xì)節(jié)的一種封裝诲宇;我們編寫一個(gè)類就是對數(shù)據(jù)和數(shù)據(jù)操作的封裝』谭可以說姑蓝,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口(可以想想普通洗衣機(jī)和全自動(dòng)洗衣機(jī)的差別吕粗,明顯全自動(dòng)洗衣機(jī)封裝更好因此操作起來更簡單纺荧;我們現(xiàn)在使用的智能手機(jī)也是封裝得足夠好的,因?yàn)閹讉€(gè)按鍵就搞定了所有的事情)颅筋。
  • 多態(tài)性:多態(tài)性是指允許不同子類型的對象對同一消息作出不同的響應(yīng)宙暇。簡單的說就是用同樣的對象引用調(diào)用同樣的方法但是做了不同的事情。多態(tài)性分為編譯時(shí)的多態(tài)性和運(yùn)行時(shí)的多態(tài)性议泵。如果將對象的方法視為對象向外界提供的服務(wù)占贫,那么運(yùn)行時(shí)的多態(tài)性可以解釋為:當(dāng)A系統(tǒng)訪問B系統(tǒng)提供的服務(wù)時(shí),B系統(tǒng)有多種提供服務(wù)的方式先口,但一切對A系統(tǒng)來說都是透明的(就像電動(dòng)剃須刀是A系統(tǒng)型奥,它的供電系統(tǒng)是B系統(tǒng),B系統(tǒng)可以使用電池供電或者用交流電碉京,甚至還有可能是太陽能桩引,A系統(tǒng)只會(huì)通過B類對象調(diào)用供電的方法,但并不知道供電系統(tǒng)的底層實(shí)現(xiàn)是什么收夸,究竟通過何種方式獲得了動(dòng)力)。方法重載(overload)實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性(也稱為前綁定)血崭,而方法重寫(override)實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性(也稱為后綁定)卧惜。運(yùn)行時(shí)的多態(tài)是面向?qū)ο笞罹璧臇|西厘灼,要實(shí)現(xiàn)多態(tài)需要做兩件事:1). 方法重寫(子類繼承父類并重寫父類中已有的或抽象的方法);2). 對象造型(用父類型引用引用子類型對象咽瓷,這樣同樣的引用調(diào)用同樣的方法就會(huì)根據(jù)子類對象的不同而表現(xiàn)出不同的行為)设凹。
String 是最基本的數(shù)據(jù)類型嗎?

不是茅姜。Java中的基本數(shù)據(jù)類型只有8個(gè):byte闪朱、short、int钻洒、long奋姿、float、double素标、char称诗、boolean;除了基本類型(primitive type)和枚舉類型(enumeration type)头遭,剩下的都是引用類型(reference type)寓免。

float f=3.4;是否正確?

不正確计维。3.4是雙精度數(shù)袜香,將雙精度型(double)賦值給浮點(diǎn)型(float)屬于下轉(zhuǎn)型(down-casting,也稱為窄化)會(huì)造成精度損失鲫惶,因此需要強(qiáng)制類型轉(zhuǎn)換float f =(float)3.4; 或者寫成float f =3.4F;蜈首。

short s1 = 1; s1 = s1 + 1;有錯(cuò)嗎?short s1 = 1; s1 += 1;有錯(cuò)嗎?

對于short s1 = 1; s1 = s1 + 1;由于1是int類型剑按,因此s1+1運(yùn)算結(jié)果也是int 型疾就,需要強(qiáng)制轉(zhuǎn)換類型才能賦值給short型。而short s1 = 1; s1 += 1;可以正確編譯艺蝴,因?yàn)閟1+= 1;相當(dāng)于s1 = (short)(s1 + 1);其中有隱含的強(qiáng)制類型轉(zhuǎn)換猬腰。

Java有沒有g(shù)oto?

goto 是Java中的保留字猜敢,在目前版本的Java中沒有使用姑荷。(根據(jù)James Gosling(Java之父)編寫的《The Java Programming Language》一書的附錄中給出了一個(gè)Java關(guān)鍵字列表,其中有g(shù)oto和const缩擂,但是這兩個(gè)是目前無法使用的關(guān)鍵字鼠冕,因此有些地方將其稱之為保留字,其實(shí)保留字這個(gè)詞應(yīng)該有更廣泛的意義胯盯,因?yàn)槭煜語言的程序員都知道懈费,在系統(tǒng)類庫中使用過的有特殊意義的單詞或單詞的組合都被視為保留字)

int和Integer有什么區(qū)別?

Java是一個(gè)近乎純潔的面向?qū)ο缶幊陶Z言博脑,但是為了編程的方便還是引入了基本數(shù)據(jù)類型憎乙,但是為了能夠?qū)⑦@些基本數(shù)據(jù)類型當(dāng)成對象操作票罐,Java為每一個(gè)基本數(shù)據(jù)類型都引入了對應(yīng)的包裝類型(wrapper class),int的包裝類就是Integer泞边,從Java 5開始引入了自動(dòng)裝箱/拆箱機(jī)制该押,使得二者可以相互轉(zhuǎn)換。
Java 為每個(gè)原始類型提供了包裝類型:

  • 原始類型: boolean阵谚,char蚕礼,byte,short梢什,int奠蹬,long,float绳矩,double

  • 包裝類型:Boolean罩润,Character,Byte翼馆,Short割以,Integer,Long应媚,F(xiàn)loat严沥,Double
    class AutoUnboxingTest {

    public static void main(String[] args) {
    Integer a = new Integer(3);
    Integer b = 3;
    int c = 3;
    System.out.println(a == b);
    System.out.println(a == c);
    }
    }
    最近還遇到一個(gè)面試題,也是和自動(dòng)裝箱和拆箱有點(diǎn)關(guān)系的中姜,代碼如下所示:

public class Test03 {

public static void main(String[] args) {
    Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;

    System.out.println(f1 == f2);
    System.out.println(f3 == f4);
}

}
如果不明就里很容易認(rèn)為兩個(gè)輸出要么都是true要么都是false消玄。首先需要注意的是f1、f2丢胚、f3翩瓜、f4四個(gè)變量都是Integer對象引用,所以下面的==運(yùn)算比較的不是值而是引用携龟。裝箱的本質(zhì)是什么呢兔跌?當(dāng)我們給一個(gè)Integer對象賦一個(gè)int值的時(shí)候,會(huì)調(diào)用Integer類的靜態(tài)方法valueOf峡蟋,如果看看valueOf的源代碼就知道發(fā)生了什么坟桅。

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= integercache.high)="" return="" integercache.cache[i="" +="" (-integercache.low)];="" new="" integer(i);="" }<="" code="">

IntegerCache是Integer的內(nèi)部類,其代碼如下所示:

/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

簡單的說蕊蝗,如果整型字面量的值在-128到127之間仅乓,那么不會(huì)new新的Integer對象,而是直接引用常量池中的Integer對象蓬戚,所以上面的面試題中f1==f2的結(jié)果是true夸楣,而f3==f4的結(jié)果是false。

&和&&的區(qū)別?

&運(yùn)算符有兩種用法:(1)按位與裕偿;(2)邏輯與洞慎。&&運(yùn)算符是短路與運(yùn)算。邏輯與跟短路與的差別是非常巨大的嘿棘,雖然二者都要求運(yùn)算符左右兩端的布爾值都是true整個(gè)表達(dá)式的值才是true。&&之所以稱為短路運(yùn)算是因?yàn)樾袢蓿绻?amp;&左邊的表達(dá)式的值是false鸟妙,右邊的表達(dá)式會(huì)被直接短路掉,不會(huì)進(jìn)行運(yùn)算挥吵。很多時(shí)候我們可能都需要用&&而不是&重父,例如在驗(yàn)證用戶登錄時(shí)判定用戶名不是null而且不是空字符串,應(yīng)當(dāng)寫為:username != null &&!username.equals("")忽匈,二者的順序不能交換房午,更不能用&運(yùn)算符,因?yàn)榈谝粋€(gè)條件如果不成立丹允,根本不能進(jìn)行字符串的equals比較郭厌,否則會(huì)產(chǎn)生NullPointerException異常。注意:邏輯或運(yùn)算符(|)和短路或運(yùn)算符(||)的差別也是如此雕蔽。

解釋內(nèi)存中的棧(stack)折柠、堆(heap)和靜態(tài)區(qū)(static area)的用法。

通常我們定義一個(gè)基本數(shù)據(jù)類型的變量批狐,一個(gè)對象的引用扇售,還有就是函數(shù)調(diào)用的現(xiàn)場保存都使用內(nèi)存中的棧空間嚣艇;而通過new關(guān)鍵字和構(gòu)造器創(chuàng)建的對象放在堆空間承冰;程序中的字面量(literal)如直接書寫的100、"hello"和常量都是放在靜態(tài)區(qū)中食零。椑梗空間操作起來最快但是棧很小,通常大量的對象都是放在堆空間慌洪,理論上整個(gè)內(nèi)存沒有被其他進(jìn)程使用的空間甚至硬盤上的虛擬內(nèi)存都可以被當(dāng)成堆空間來使用顶燕。

String str = new String("hello");
上面的語句中變量str放在棧上,用new創(chuàng)建出來的字符串對象放在堆上冈爹,而"hello"這個(gè)字面量放在靜態(tài)區(qū)涌攻。

Math.round(11.5) 等于多少?Math.round(-11.5)等于多少频伤?

Math.round(11.5)的返回值是12恳谎,Math.round(-11.5)的返回值是-11。四舍五入的原理是在參數(shù)上加0.5然后進(jìn)行下取整。

switch 是否能作用在byte 上因痛,是否能作用在long 上婚苹,是否能作用在String上?

在Java 5以前鸵膏,switch(expr)中膊升,expr只能是byte、short谭企、char廓译、int。從Java 5開始债查,Java中引入了枚舉類型非区,expr也可以是enum類型,從Java 7開始盹廷,expr還可以是字符串(String)征绸,但是長整型(long)在目前所有的版本中都是不可以的。

數(shù)組有沒有l(wèi)ength()方法俄占?String有沒有l(wèi)ength()方法管怠?

數(shù)組沒有l(wèi)ength()方法,有l(wèi)ength 的屬性颠放。String 有l(wèi)ength()方法排惨。JavaScript中,獲得字符串的長度是通過length屬性得到的碰凶,這一點(diǎn)容易和Java混淆暮芭。

在Java中,如何跳出當(dāng)前的多重嵌套循環(huán)欲低?

在最外層循環(huán)前加一個(gè)標(biāo)記如A辕宏,然后用break A;可以跳出多重循環(huán)。(Java中支持帶標(biāo)簽的break和continue語句砾莱,作用有點(diǎn)類似于C和C++中的goto語句瑞筐,但是就像要避免使用goto一樣,應(yīng)該避免使用帶標(biāo)簽的break和continue腊瑟,因?yàn)樗粫?huì)讓你的程序變得更優(yōu)雅聚假,很多時(shí)候甚至有相反的作用,所以這種語法其實(shí)不知道更好)

構(gòu)造器(constructor)是否可被重寫(override)闰非?

構(gòu)造器不能被繼承膘格,因此不能被重寫,但可以被重載财松。

兩個(gè)對象值相同(x.equals(y) == true)瘪贱,但卻可有不同的hash code纱控,這句話對不對?

不對菜秦,如果兩個(gè)對象x和y滿足x.equals(y) == true甜害,它們的哈希碼(hash code)應(yīng)當(dāng)相同。Java對于eqauls方法和hashCode方法是這樣規(guī)定的:(1)如果兩個(gè)對象相同(equals方法返回true)球昨,那么它們的hashCode值一定要相同尔店;(2)如果兩個(gè)對象的hashCode相同,它們并不一定相同褪尝。當(dāng)然闹获,你未必要按照要求去做,但是如果你違背了上述原則就會(huì)發(fā)現(xiàn)在使用容器時(shí)河哑,相同的對象可以出現(xiàn)在Set集合中,同時(shí)增加新元素的效率會(huì)大大下降(對于使用哈希存儲(chǔ)的系統(tǒng)龟虎,如果哈希碼頻繁的沖突將會(huì)造成存取性能急劇下降)璃谨。

是否可以繼承String類?

String 類是final類鲤妥,不可以被繼承佳吞。

當(dāng)一個(gè)對象被當(dāng)作參數(shù)傳遞到一個(gè)方法后,此方法可改變這個(gè)對象的屬性棉安,并可返回變化后的結(jié)果底扳,那么這里到底是值傳遞還是引用傳遞?

是值傳遞贡耽。Java語言的方法調(diào)用只支持參數(shù)的值傳遞衷模。當(dāng)一個(gè)對象實(shí)例作為一個(gè)參數(shù)被傳遞到方法中時(shí),參數(shù)的值就是對該對象的引用蒲赂。對象的屬性可以在被調(diào)用過程中被改變阱冶,但對對象引用的改變是不會(huì)影響到調(diào)用者的。C++和C#中可以通過傳引用或傳輸出參數(shù)來改變傳入的參數(shù)的值滥嘴。在C#中可以編寫如下所示的代碼木蹬,但是在Java中卻做不到。

String和StringBuilder若皱、StringBuffer的區(qū)別镊叁?

Java平臺(tái)提供了兩種類型的字符串:String和StringBuffer/StringBuilder,它們可以儲(chǔ)存和操作字符串走触。其中String是只讀字符串晦譬,也就意味著String引用的字符串內(nèi)容是不能被改變的。而StringBuffer/StringBuilder類表示的字符串對象可以直接進(jìn)行修改饺汹。StringBuilder是Java 5中引入的蛔添,它和StringBuffer的方法完全相同,區(qū)別在于它是在單線程環(huán)境下使用的,因?yàn)樗乃蟹矫娑紱]有被synchronized修飾迎瞧,因此它的效率也比StringBuffer要高

重載(Overload)和重寫(Override)的區(qū)別夸溶。重載的方法能否根據(jù)返回類型進(jìn)行區(qū)分?

方法的重載和重寫都是實(shí)現(xiàn)多態(tài)的方式凶硅,區(qū)別在于前者實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性缝裁,而后者實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性。重載發(fā)生在一個(gè)類中足绅,同名的方法如果有不同的參數(shù)列表(參數(shù)類型不同捷绑、參數(shù)個(gè)數(shù)不同或者二者都不同)則視為重載;重寫發(fā)生在子類與父類之間氢妈,重寫要求子類被重寫方法與父類被重寫方法有相同的返回類型粹污,比父類被重寫方法更好訪問,不能比父類被重寫方法聲明更多的異常(里氏代換原則)首量。重載對返回類型沒有特殊的要求壮吩。

描述一下JVM加載class文件的原理機(jī)制?

JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實(shí)現(xiàn)的加缘,Java中的類加載器是一個(gè)重要的Java運(yùn)行時(shí)系統(tǒng)組件鸭叙,它負(fù)責(zé)在運(yùn)行時(shí)查找和裝入類文件中的類。
由于Java的跨平臺(tái)性拣宏,經(jīng)過編譯的Java源程序并不是一個(gè)可執(zhí)行程序沈贝,而是一個(gè)或多個(gè)類文件。當(dāng)Java程序需要使用某個(gè)類時(shí)勋乾,JVM會(huì)確保這個(gè)類已經(jīng)被加載宋下、連接(驗(yàn)證、準(zhǔn)備和解析)和初始化市俊。類的加載是指把類的.class文件中的數(shù)據(jù)讀入到內(nèi)存中杨凑,通常是創(chuàng)建一個(gè)字節(jié)數(shù)組讀入.class文件,然后產(chǎn)生與所加載類對應(yīng)的Class對象摆昧。加載完成后撩满,Class對象還不完整,所以此時(shí)的類還不可用绅你。當(dāng)類被加載后就進(jìn)入連接階段伺帘,這一階段包括驗(yàn)證、準(zhǔn)備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認(rèn)的初始值)和解析(將符號(hào)引用替換為直接引用)三個(gè)步驟忌锯。最后JVM對類進(jìn)行初始化伪嫁,包括:1)如果類存在直接的父類并且這個(gè)類還沒有被初始化,那么就先初始化父類偶垮;2)如果類中存在初始化語句张咳,就依次執(zhí)行這些初始化語句帝洪。
類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)脚猾、擴(kuò)展加載器(Extension)葱峡、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始龙助,類加載過程采取了父親委托機(jī)制(PDM)砰奕。PDM更好的保證了Java平臺(tái)的安全性,在該機(jī)制中提鸟,JVM自帶的Bootstrap是根加載器军援,其他的加載器都有且僅有一個(gè)父類加載器。類的加載首先請求父類加載器加載称勋,父類加載器無能為力時(shí)才由其子類加載器自行加載胸哥。JVM不會(huì)向Java程序提供對Bootstrap的引用。下面是關(guān)于幾個(gè)類加載器的說明:

Bootstrap:一般用本地代碼實(shí)現(xiàn)赡鲜,負(fù)責(zé)加載JVM基礎(chǔ)核心類庫(rt.jar)烘嘱;
Extension:從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫,它的父加載器是Bootstrap蝗蛙;
System:又叫應(yīng)用類加載器,其父類是Extension醉鳖。它是應(yīng)用最廣泛的類加載器捡硅。它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中記載類,是用戶自定義加載器的默認(rèn)父加載器盗棵。

char 型變量中能不能存貯一個(gè)中文漢字壮韭,為什么?

char類型可以存儲(chǔ)一個(gè)中文漢字纹因,因?yàn)镴ava中使用的編碼是Unicode(不選擇任何特定的編碼喷屋,直接使用字符在字符集中的編號(hào),這是統(tǒng)一的唯一方法)瞭恰,一個(gè)char類型占2個(gè)字節(jié)(16比特)屯曹,所以放一個(gè)中文是沒問題的。

抽象類(abstract class)和接口(interface)有什么異同惊畏?

抽象類和接口都不能夠?qū)嵗竦ⅲ梢远x抽象類和接口類型的引用。一個(gè)類如果繼承了某個(gè)抽象類或者實(shí)現(xiàn)了某個(gè)接口都需要對其中的抽象方法全部進(jìn)行實(shí)現(xiàn)颜启,否則該類仍然需要被聲明為抽象類偷俭。接口比抽象類更加抽象,因?yàn)槌橄箢愔锌梢远x構(gòu)造器缰盏,可以有抽象方法和具體方法涌萤,而接口中不能定義構(gòu)造器而且其中的方法全部都是抽象方法淹遵。抽象類中的成員可以是private、默認(rèn)负溪、protected透揣、public的,而接口中的成員全都是public的笙以。抽象類中可以定義成員變量淌实,而接口中定義的成員變量實(shí)際上都是常量。有抽象方法的類必須被聲明為抽象類猖腕,而抽象類未必要有抽象方法拆祈。

靜態(tài)嵌套類(Static Nested Class)和內(nèi)部類(Inner Class)的不同?

Static Nested Class是被聲明為靜態(tài)(static)的內(nèi)部類倘感,它可以不依賴于外部類實(shí)例被實(shí)例化放坏。而通常的內(nèi)部類需要在外部類實(shí)例化后才能實(shí)例化。
Java中非靜態(tài)內(nèi)部類對象的創(chuàng)建要依賴其外部類對象老玛,上面的面試題中foo和main方法都是靜態(tài)方法淤年,靜態(tài)方法中沒有this,也就是說沒有所謂的外部類對象蜡豹,因此無法創(chuàng)建內(nèi)部類對象麸粮。

Java 中會(huì)存在內(nèi)存泄漏嗎,請簡單描述镜廉。

理論上Java因?yàn)橛欣厥諜C(jī)制(GC)不會(huì)存在內(nèi)存泄露問題(這也是Java被廣泛使用于服務(wù)器端編程的一個(gè)重要原因)弄诲;然而在實(shí)際開發(fā)中,可能會(huì)存在無用但可達(dá)的對象娇唯,這些對象不能被GC回收齐遵,因此也會(huì)導(dǎo)致內(nèi)存泄露的發(fā)生。例如Hibernate的Session(一級緩存)中的對象屬于持久態(tài)塔插,垃圾回收器是不會(huì)回收這些對象的梗摇,然而這些對象中可能存在無用的垃圾對象,如果不及時(shí)關(guān)閉(close)或清空(flush)一級緩存就可能導(dǎo)致內(nèi)存泄露想许。下面例子中的代碼也會(huì)導(dǎo)致內(nèi)存泄露伶授。然而其中的pop方法卻存在內(nèi)存泄露的問題,當(dāng)我們用pop方法彈出棧中的對象時(shí)伸刃,該對象不會(huì)被當(dāng)作垃圾回收谎砾,即使使用棧的程序不再引用這些對象,因?yàn)闂?nèi)部維護(hù)著對這些對象的過期引用(obsolete reference)捧颅。在支持垃圾回收的語言中景图,內(nèi)存泄露是很隱蔽的,這種內(nèi)存泄露其實(shí)就是無意識(shí)的對象保持碉哑。如果一個(gè)對象引用被無意識(shí)的保留起來了挚币,那么垃圾回收器不會(huì)處理這個(gè)對象亮蒋,也不會(huì)處理該對象引用的其他對象,即使這樣的對象只有少數(shù)幾個(gè)妆毕,也可能會(huì)導(dǎo)致很多的對象被排除在垃圾回收之外慎玖,從而對性能造成重大影響,極端情況下會(huì)引發(fā)Disk Paging(物理內(nèi)存與硬盤的虛擬內(nèi)存交換數(shù)據(jù))笛粘,甚至造成OutOfMemoryError趁怔。

抽象的(abstract)方法是否可同時(shí)是靜態(tài)的(static),是否可同時(shí)是本地方法(native),是否可同時(shí)被synchronized修飾薪前?

都不能润努。抽象方法需要子類重寫,而靜態(tài)的方法是無法被重寫的示括,因此二者是矛盾的铺浇。本地方法是由本地代碼(如C代碼)實(shí)現(xiàn)的方法,而抽象方法是沒有實(shí)現(xiàn)的垛膝,也是矛盾的鳍侣。synchronized和方法的實(shí)現(xiàn)細(xì)節(jié)有關(guān),抽象方法不涉及實(shí)現(xiàn)細(xì)節(jié)吼拥,因此也是相互矛盾的倚聚。

闡述靜態(tài)變量和實(shí)例變量的區(qū)別。

靜態(tài)變量是被static修飾符修飾的變量凿可,也稱為類變量秉沼,它屬于類,不屬于類的任何一個(gè)對象矿酵,一個(gè)類不管創(chuàng)建多少個(gè)對象,靜態(tài)變量在內(nèi)存中有且僅有一個(gè)拷貝矗积;實(shí)例變量必須依存于某一實(shí)例全肮,需要先創(chuàng)建對象然后通過對象才能訪問到它。靜態(tài)變量可以實(shí)現(xiàn)讓多個(gè)對象共享內(nèi)存棘捣。

是否可以從一個(gè)靜態(tài)(static)方法內(nèi)部發(fā)出對非靜態(tài)(non-static)方法的調(diào)用辜腺?

不可以,靜態(tài)方法只能訪問靜態(tài)成員乍恐,因?yàn)榉庆o態(tài)方法的調(diào)用要先創(chuàng)建對象评疗,在調(diào)用靜態(tài)方法時(shí)可能對象并沒有被初始化灰追。

如何實(shí)現(xiàn)對象克缕凇?

有兩種方式:
??1). 實(shí)現(xiàn)Cloneable接口并重寫Object類中的clone()方法习霹;
??2). 實(shí)現(xiàn)Serializable接口呜投,通過對象的序列化和反序列化實(shí)現(xiàn)克隆加匈,可以實(shí)現(xiàn)真正的深度克隆存璃。

GC是什么?為什么要有GC雕拼?

GC是垃圾收集的意思纵东,內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯(cuò)誤的內(nèi)存回收會(huì)導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰啥寇,Java提供的GC功能可以自動(dòng)監(jiān)測對象是否超過作用域從而達(dá)到自動(dòng)回收內(nèi)存的目的偎球,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法。Java程序員不用擔(dān)心內(nèi)存管理辑甜,因?yàn)槔占鲿?huì)自動(dòng)進(jìn)行管理衰絮。要請求垃圾收集,可以調(diào)用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() 栈戳,但JVM可以屏蔽掉顯示的垃圾回收調(diào)用岂傲。
垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存子檀。垃圾回收器通常是作為一個(gè)單獨(dú)的低優(yōu)先級的線程運(yùn)行镊掖,不可預(yù)知的情況下對內(nèi)存堆中已經(jīng)死亡的或者長時(shí)間沒有使用的對象進(jìn)行清除和回收,程序員不能實(shí)時(shí)的調(diào)用垃圾回收器對某個(gè)對象或所有對象進(jìn)行垃圾回收褂痰。在Java誕生初期亩进,垃圾回收是Java最大的亮點(diǎn)之一,因?yàn)榉?wù)器端的編程需要有效的防止內(nèi)存泄露問題缩歪,然而時(shí)過境遷归薛,如今Java的垃圾回收機(jī)制已經(jīng)成為被詬病的東西。移動(dòng)智能終端用戶通常覺得iOS的系統(tǒng)比Android系統(tǒng)有更好的用戶體驗(yàn)匪蝙,其中一個(gè)深層次的原因就在于Android系統(tǒng)中垃圾回收的不可預(yù)知性主籍。
垃圾回收機(jī)制有很多種,包括:分代復(fù)制垃圾回收逛球、標(biāo)記垃圾回收千元、增量垃圾回收等方式。標(biāo)準(zhǔn)的Java進(jìn)程既有棧又有堆颤绕。棧保存了原始型局部變量幸海,堆保存了要?jiǎng)?chuàng)建的對象。Java平臺(tái)對堆內(nèi)存回收和再利用的基本算法被稱為標(biāo)記和清除奥务,但是Java對其進(jìn)行了改進(jìn)物独,采用“分代式垃圾收集”。這種方法會(huì)跟Java對象的生命周期將堆內(nèi)存劃分為不同的區(qū)域氯葬,在垃圾收集過程中挡篓,可能會(huì)將對象移動(dòng)到不同區(qū)域:

  • 伊甸園(Eden):這是對象最初誕生的區(qū)域,并且對大多數(shù)對象來說帚称,這里是它們唯一存在過的區(qū)域瞻凤。
  • 幸存者樂園(Survivor):從伊甸園幸存下來的對象會(huì)被挪到這里憨攒。
  • 終身頤養(yǎng)園(Tenured):這是足夠老的幸存對象的歸宿。年輕代收集(Minor-GC)過程是不會(huì)觸及這個(gè)地方的阀参。當(dāng)年輕代收集不能把對象放進(jìn)終身頤養(yǎng)園時(shí)肝集,就會(huì)觸發(fā)一次完全收集(Major-GC),這里可能還會(huì)牽扯到壓縮蛛壳,以便為大對象騰出足夠的空間杏瞻。
String s = new String("xyz");創(chuàng)建了幾個(gè)字符串對象?

兩個(gè)對象衙荐,一個(gè)是靜態(tài)區(qū)的"xyz"捞挥,一個(gè)是用new創(chuàng)建在堆上的對象。

接口是否可繼承(extends)接口忧吟?抽象類是否可實(shí)現(xiàn)(implements)接口砌函?抽象類是否可繼承具體類(concrete class)?

接口可以繼承接口溜族,而且支持多重繼承讹俊。抽象類可以實(shí)現(xiàn)(implements)接口,抽象類可繼承具體類也可以繼承抽象類煌抒。

一個(gè)".java"源文件中是否可以包含多個(gè)類(不是內(nèi)部類)仍劈?有什么限制?

可以寡壮,但一個(gè)源文件中最多只能有一個(gè)公開類(public class)而且文件名必須和公開類的類名完全保持一致贩疙。

Anonymous Inner Class(匿名內(nèi)部類)是否可以繼承其它類?是否可以實(shí)現(xiàn)接口况既?

可以繼承其他類或?qū)崿F(xiàn)其他接口这溅,在Swing編程和Android開發(fā)中常用此方式來實(shí)現(xiàn)事件監(jiān)聽和回調(diào)。

內(nèi)部類可以引用它的包含類(外部類)的成員嗎棒仍?有沒有什么限制芍躏?

一個(gè)內(nèi)部類對象可以訪問創(chuàng)建它的外部類對象的成員,包括私有成員降狠。

Java 中的final關(guān)鍵字有哪些用法?

(1)修飾類:表示該類不能被繼承庇楞;(2)修飾方法:表示方法不能被重寫榜配;(3)修飾變量:表示變量只能一次賦值以后值不能被修改(常量)。

數(shù)據(jù)類型之間的轉(zhuǎn)換:
  • 如何將字符串轉(zhuǎn)換為基本數(shù)據(jù)類型吕晌?
  • 如何將基本數(shù)據(jù)類型轉(zhuǎn)換為字符串蛋褥?
  • 調(diào)用基本數(shù)據(jù)類型對應(yīng)的包裝類中的方法parseXXX(String)或valueOf(String)即可返回相應(yīng)基本類型;
  • 一種方法是將基本數(shù)據(jù)類型與空字符串("")連接(+)即可獲得其所對應(yīng)的字符串睛驳;另一種方法是調(diào)用String 類中的valueOf()方法返回相應(yīng)字符串
如何實(shí)現(xiàn)字符串的反轉(zhuǎn)及替換烙心?

方法很多膜廊,可以自己寫實(shí)現(xiàn)也可以使用String或StringBuffer/StringBuilder中的方法。有一道很常見的面試題是用遞歸實(shí)現(xiàn)字符串反轉(zhuǎn)淫茵,代碼如下所示:

public static String reverse(String originStr) {
    if(originStr == null || originStr.length() <= 1)="" return="" originstr;="" reverse(originstr.substring
日期和時(shí)間:
  • 如何取得年月日爪瓜、小時(shí)分鐘秒?
  • 如何取得從1970年1月1日0時(shí)0分0秒到現(xiàn)在的毫秒數(shù)匙瘪?
  • 如何取得某月的最后一天铆铆?
  • 如何格式化日期?
    問題1:創(chuàng)建java.util.Calendar 實(shí)例丹喻,調(diào)用其get()方法傳入不同的參數(shù)即可獲得參數(shù)所對應(yīng)的值薄货。Java 8中可以使用java.time.LocalDateTimel來獲取,代碼如下所示碍论。
public class DateTimeTest {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance()
        System.out.println(cal.get(Calendar.YEAR))
        System.out.println(cal.get(Calendar.MONTH))
        System.out.println(cal.get(Calendar.DATE))
        System.out.println(cal.get(Calendar.HOUR_OF_DAY))
        System.out.println(cal.get(Calendar.MINUTE))
        System.out.println(cal.get(Calendar.SECOND))

        // Java 8
        LocalDateTime dt = LocalDateTime.now()
        System.out.println(dt.getYear())
        System.out.println(dt.getMonthValue())
        System.out.println(dt.getDayOfMonth())
        System.out.println(dt.getHour())
        System.out.println(dt.getMinute())
        System.out.println(dt.getSecond())
    }
}

問題2:以下方法均可獲得該毫秒數(shù)谅猾。

Calendar.getInstance().getTimeInMillis()
System.currentTimeMillis()
Clock.systemDefaultZone().millis()

問題3:代碼如下所示。

Calendar time = Calendar.getInstance()
time.getActualMaximum(Calendar.DAY_OF_MONTH)

問題4:利用java.text.DataFormat 的子類(如SimpleDateFormat類)中的format(Date)方法可將日期格式化鳍悠。Java 8中可以用java.time.format.DateTimeFormatter來格式化時(shí)間日期税娜,代碼如下所示。

import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.Date

class DateFormatTest {

    public static void main(String[] args) {
        SimpleDateFormat oldFormatter = new SimpleDateFormat("yyyy/MM/dd")
        Date date1 = new Date()
        System.out.println(oldFormatter.format(date1))

        // Java 8
        DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd")
        LocalDate date2 = LocalDate.now()
        System.out.println(date2.format(newFormatter))
    }
打印昨天的當(dāng)前時(shí)刻贼涩。
import java.util.Calendar

class YesterdayCurrent {
    public static void main(String[] args){
        Calendar cal = Calendar.getInstance()
        cal.add(Calendar.DATE, -1)
        System.out.println(cal.getTime())
    }
}
在Java 8中巧涧,可以用下面的代碼實(shí)現(xiàn)相同的功能。

import java.time.LocalDateTime;

class YesterdayCurrent {

    public static void main(String[] args) {
        LocalDateTime today = LocalDateTime.now();
        LocalDateTime yesterday = today.minusDays(1);

        System.out.println(yesterday);
    }
}
比較一下Java和JavaSciprt遥倦。

JavaScript 與Java是兩個(gè)公司開發(fā)的不同的兩個(gè)產(chǎn)品谤绳。Java 是原Sun Microsystems公司推出的面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,特別適合于互聯(lián)網(wǎng)應(yīng)用程序開發(fā)袒哥;而JavaScript是Netscape公司的產(chǎn)品缩筛,為了擴(kuò)展Netscape瀏覽器的功能而開發(fā)的一種可以嵌入Web頁面中運(yùn)行的基于對象和事件驅(qū)動(dòng)的解釋性語言。JavaScript的前身是LiveScript堡称;而Java的前身是Oak語言瞎抛。
下面對兩種語言間的異同作如下比較:

  • 基于對象和面向?qū)ο螅篔ava是一種真正的面向?qū)ο蟮恼Z言,即使是開發(fā)簡單的程序却紧,必須設(shè)計(jì)對象桐臊;JavaScript是種腳本語言,它可以用來制作與網(wǎng)絡(luò)無關(guān)的晓殊,與用戶交互作用的復(fù)雜軟件断凶。它是一種基于對象(Object-Based)和事件驅(qū)動(dòng)(Event-Driven)的編程語言,因而它本身提供了非常豐富的內(nèi)部對象供設(shè)計(jì)人員使用巫俺。
  • 解釋和編譯:Java的源代碼在執(zhí)行之前认烁,必須經(jīng)過編譯。JavaScript是一種解釋性編程語言,其源代碼不需經(jīng)過編譯却嗡,由瀏覽器解釋執(zhí)行舶沛。(目前的瀏覽器幾乎都使用了JIT(即時(shí)編譯)技術(shù)來提升JavaScript的運(yùn)行效率)
  • 強(qiáng)類型變量和類型弱變量:Java采用強(qiáng)類型變量檢查,即所有變量在編譯之前必須作聲明窗价;JavaScript中變量是弱類型的如庭,甚至在使用變量前可以不作聲明,JavaScript的解釋器在運(yùn)行時(shí)檢查推斷其數(shù)據(jù)類型舌镶。
  • 代碼格式不一樣柱彻。
Error和Exception有什么區(qū)別?

Error表示系統(tǒng)級的錯(cuò)誤和程序不必處理的異常餐胀,是恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問題哟楷;比如內(nèi)存溢出,不可能指望程序能處理這樣的情況否灾;Exception表示需要捕捉或者需要程序進(jìn)行處理的異常卖擅,是一種設(shè)計(jì)或?qū)崿F(xiàn)問題;也就是說墨技,它表示如果程序運(yùn)行正常惩阶,從不會(huì)發(fā)生的情況。

try{}里有一個(gè)return語句扣汪,那么緊跟在這個(gè)try后的finally{}里的代碼會(huì)不會(huì)被執(zhí)行断楷,什么時(shí)候被執(zhí)行,在return前還是后?

會(huì)執(zhí)行崭别,在方法返回調(diào)用者前執(zhí)行冬筒。
在finally中改變返回值的做法是不好的,因?yàn)槿绻嬖趂inally代碼塊茅主,try中的return語句不會(huì)立馬返回調(diào)用者舞痰,而是記錄下返回值待finally代碼塊執(zhí)行完畢之后再向調(diào)用者返回其值,然后如果在finally中修改了返回值诀姚,就會(huì)返回修改后的值响牛。顯然,在finally中返回或者修改返回值會(huì)對程序造成很大的困擾赫段,C#中直接用編譯錯(cuò)誤的方式來阻止程序員干這種齷齪的事情呀打,Java中也可以通過提升編譯器的語法檢查級別來產(chǎn)生警告或錯(cuò)誤,Eclipse中可以在如圖所示的地方進(jìn)行設(shè)置糯笙,強(qiáng)烈建議將此項(xiàng)設(shè)置為編譯錯(cuò)誤贬丛。

Java語言如何進(jìn)行異常處理,關(guān)鍵字:throws炬丸、throw、try、catch稠炬、finally分別如何使用焕阿?

Java通過面向?qū)ο蟮姆椒ㄟM(jìn)行異常處理,把各種不同的異常進(jìn)行分類首启,并提供了良好的接口暮屡。在Java中,每個(gè)異常都是一個(gè)對象毅桃,它是Throwable類或其子類的實(shí)例褒纲。當(dāng)一個(gè)方法出現(xiàn)異常后便拋出一個(gè)異常對象,該對象中包含有異常信息钥飞,調(diào)用這個(gè)對象的方法可以捕獲到這個(gè)異常并可以對其進(jìn)行處理莺掠。Java的異常處理是通過5個(gè)關(guān)鍵詞來實(shí)現(xiàn)的:try、catch读宙、throw彻秆、throws和finally。一般情況下是用try來執(zhí)行一段程序结闸,如果系統(tǒng)會(huì)拋出(throw)一個(gè)異常對象唇兑,可以通過它的類型來捕獲(catch)它,或通過總是執(zhí)行代碼塊(finally)來處理桦锄;try用來指定一塊預(yù)防所有異常的程序扎附;catch子句緊跟在try塊后面,用來指定你想要捕獲的異常的類型结耀;throw語句用來明確地拋出一個(gè)異常留夜;throws用來聲明一個(gè)方法可能拋出的各種異常(當(dāng)然聲明異常時(shí)允許無病呻吟);finally為確保一段代碼不管發(fā)生什么異常狀況都要被執(zhí)行饼记;try語句可以嵌套香伴,每當(dāng)遇到一個(gè)try語句,異常的結(jié)構(gòu)就會(huì)被放入異常棧中具则,直到所有的try語句都完成即纲。如果下一級的try語句沒有對某種異常進(jìn)行處理,異常棧就會(huì)執(zhí)行出棧操作博肋,直到遇到有處理這種異常的try語句或者最終將異常拋給JVM低斋。

運(yùn)行時(shí)異常與受檢異常有何異同?

異常表示程序運(yùn)行過程中可能出現(xiàn)的非正常狀態(tài)匪凡,運(yùn)行時(shí)異常表示虛擬機(jī)的通常操作中可能遇到的異常膊畴,是一種常見運(yùn)行錯(cuò)誤,只要程序設(shè)計(jì)得沒有問題通常就不會(huì)發(fā)生病游。受檢異常跟程序運(yùn)行的上下文環(huán)境有關(guān)唇跨,即使程序設(shè)計(jì)無誤稠通,仍然可能因使用的問題而引發(fā)。Java編譯器要求方法必須聲明拋出可能發(fā)生的受檢異常买猖,但是并不要求必須聲明拋出未被捕獲的運(yùn)行時(shí)異常改橘。異常和繼承一樣,是面向?qū)ο蟪绦蛟O(shè)計(jì)中經(jīng)常被濫用的東西玉控,在Effective Java中對異常的使用給出了以下指導(dǎo)原則:

  • 不要將異常處理用于正常的控制流(設(shè)計(jì)良好的API不應(yīng)該強(qiáng)迫它的調(diào)用者為了正常的控制流而使用異常)
  • 對可以恢復(fù)的情況使用受檢異常飞主,對編程錯(cuò)誤使用運(yùn)行時(shí)異常
  • 避免不必要的使用受檢異常(可以通過一些狀態(tài)檢測手段來避免異常的發(fā)生)
  • 優(yōu)先使用標(biāo)準(zhǔn)的異常
  • 每個(gè)方法拋出的異常都要有文檔
  • 保持異常的原子性
  • 不要在catch中忽略掉捕獲到的異常
列出一些你常見的運(yùn)行時(shí)異常?
  • ArithmeticException(算術(shù)異常)
  • ClassCastException (類轉(zhuǎn)換異常)
  • IllegalArgumentException (非法參數(shù)異常)
  • IndexOutOfBoundsException (下標(biāo)越界異常)
  • NullPointerException (空指針異常)
  • SecurityException (安全異常)
闡述final高诺、finally碌识、finalize的區(qū)別。
  • final:修飾符(關(guān)鍵字)有三種用法:如果一個(gè)類被聲明為final虱而,意味著它不能再派生出新的子類筏餐,即不能被繼承,因此它和abstract是反義詞薛窥。將變量聲明為final胖烛,可以保證它們在使用中不被改變,被聲明為final的變量必須在聲明時(shí)給定初值诅迷,而在以后的引用中只能讀取不可修改佩番。被聲明為final的方法也同樣只能使用,不能在子類中被重寫罢杉。
  • finally:通常放在try…catch…的后面構(gòu)造總是執(zhí)行代碼塊趟畏,這就意味著程序無論正常執(zhí)行還是發(fā)生異常,這里的代碼只要JVM不關(guān)閉都能執(zhí)行滩租,可以將釋放外部資源的代碼寫在finally塊中赋秀。
  • finalize:Object類中定義的方法,Java中允許使用finalize()方法在垃圾收集器將對象從內(nèi)存中清除出去之前做必要的清理工作律想。這個(gè)方法是由垃圾收集器在銷毀對象時(shí)調(diào)用的猎莲,通過重寫finalize()方法可以整理系統(tǒng)資源或者執(zhí)行其他清理工作。
類ExampleA繼承Exception技即,類ExampleB繼承ExampleA著洼。
有如下代碼片斷:

try {
    throw new ExampleB("b")
} catch(ExampleA e){
    System.out.println("ExampleA");
} catch(Exception e){
    System.out.println("Exception");
}
請問執(zhí)行此段代碼的輸出是什么? 
答:輸出:ExampleA而叼。(根據(jù)里氏代換原則[能使用父類型的地方一定能使用子類型]身笤,抓取ExampleA類型異常的catch塊能夠抓住try塊中拋出的ExampleB類型的異常)

面試題 - 說出下面代碼的運(yùn)行結(jié)果。(此題的出處是《Java編程思想》一書)
class Annoyance extends Exception {}
class Sneeze extends Annoyance {}

class Human {

    public static void main(String[] args) 
        throws Exception {
        try {
            try {
                throw new Sneeze();
            } 
            catch ( Annoyance a ) {
                System.out.println("Caught Annoyance");
                throw a;
            }
        } 
        catch ( Sneeze s ) {
            System.out.println("Caught Sneeze");
            return ;
        }
        finally {
            System.out.println("Hello World!");
        }
    }
}
List葵陵、Set液荸、Map是否繼承自Collection接口?

List脱篙、Set 是娇钱,Map 不是伤柄。Map是鍵值對映射容器,與List和Set有明顯的區(qū)別文搂,而Set存儲(chǔ)的零散的元素且不允許有重復(fù)元素(數(shù)學(xué)中的集合也是如此)响迂,List是線性結(jié)構(gòu)的容器,適用于按數(shù)值索引訪問元素的情形细疚。

闡述ArrayList、Vector川梅、LinkedList的存儲(chǔ)性能和特性疯兼。

ArrayList 和Vector都是使用數(shù)組方式存儲(chǔ)數(shù)據(jù),此數(shù)組元素?cái)?shù)大于實(shí)際存儲(chǔ)的數(shù)據(jù)以便增加和插入元素贫途,它們都允許直接按序號(hào)索引元素吧彪,但是插入元素要涉及數(shù)組元素移動(dòng)等內(nèi)存操作,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢丢早,Vector中的方法由于添加了synchronized修飾姨裸,因此Vector是線程安全的容器,但性能上較ArrayList差怨酝,因此已經(jīng)是Java中的遺留容器傀缩。LinkedList使用雙向鏈表實(shí)現(xiàn)存儲(chǔ)(將內(nèi)存中零散的內(nèi)存單元通過附加的引用關(guān)聯(lián)起來,形成一個(gè)可以按序號(hào)索引的線性結(jié)構(gòu)农猬,這種鏈?zhǔn)酱鎯?chǔ)方式與數(shù)組的連續(xù)存儲(chǔ)方式相比赡艰,內(nèi)存的利用率更高),按序號(hào)索引數(shù)據(jù)需要進(jìn)行前向或后向遍歷斤葱,但是插入數(shù)據(jù)時(shí)只需要記錄本項(xiàng)的前后項(xiàng)即可慷垮,所以插入速度較快。Vector屬于遺留容器(Java早期的版本中提供的容器揍堕,除此之外料身,Hashtable、Dictionary衩茸、BitSet芹血、Stack、Properties都是遺留容器)递瑰,已經(jīng)不推薦使用祟牲,但是由于ArrayList和LinkedListed都是非線程安全的,如果遇到多個(gè)線程操作同一個(gè)容器的場景抖部,則可以通過工具類Collections中的synchronizedList方法將其轉(zhuǎn)換成線程安全的容器后再使用(這是對裝潢模式的應(yīng)用说贝,將已有對象傳入另一個(gè)類的構(gòu)造器中創(chuàng)建新的對象來增強(qiáng)實(shí)現(xiàn))。

Collection和Collections的區(qū)別慎颗?

Collection是一個(gè)接口乡恕,它是Set言询、List等容器的父接口;Collections是個(gè)一個(gè)工具類傲宜,提供了一系列的靜態(tài)方法來輔助容器操作运杭,這些方法包括對容器的搜索、排序函卒、線程安全化等等辆憔。

歡迎關(guān)注公共號(hào)

關(guān)注公共號(hào)即可獲得最新、最全Android面試題
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末报嵌,一起剝皮案震驚了整個(gè)濱河市虱咧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锚国,老刑警劉巖腕巡,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異血筑,居然都是意外死亡绘沉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門豺总,熙熙樓的掌柜王于貴愁眉苦臉地迎上來车伞,“玉大人,你說我怎么就攤上這事喻喳√溃” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵沸枯,是天一觀的道長日矫。 經(jīng)常有香客問我,道長绑榴,這世上最難降的妖魔是什么哪轿? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮翔怎,結(jié)果婚禮上窃诉,老公的妹妹穿的比我還像新娘。我一直安慰自己赤套,他們只是感情好飘痛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著容握,像睡著了一般宣脉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剔氏,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天塑猖,我揣著相機(jī)與錄音竹祷,去河邊找鬼。 笑死羊苟,一個(gè)胖子當(dāng)著我的面吹牛塑陵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜡励,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼令花,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凉倚?” 一聲冷哼從身側(cè)響起彭则,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎占遥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體输瓜,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓦胎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尤揣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搔啊。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖北戏,靈堂內(nèi)的尸體忽然破棺而出负芋,到底是詐尸還是另有隱情,我是刑警寧澤嗜愈,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布旧蛾,位于F島的核電站,受9級特大地震影響蠕嫁,放射性物質(zhì)發(fā)生泄漏锨天。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一剃毒、第九天 我趴在偏房一處隱蔽的房頂上張望病袄。 院中可真熱鬧,春花似錦赘阀、人聲如沸益缠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幅慌。三九已至,卻和暖如春轰豆,著一層夾襖步出監(jiān)牢的瞬間欠痴,已是汗流浹背迄靠。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喇辽,地道東北人掌挚。 一個(gè)月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像菩咨,于是被迫代替她去往敵國和親吠式。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法抽米,類相關(guān)的語法特占,內(nèi)部類的語法,繼承相關(guān)的語法云茸,異常的語法是目,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司标捺,掛了不少懊纳,但最終還是拿到小米、百度亡容、阿里嗤疯、京東、新浪闺兢、CVTE茂缚、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,192評論 11 349
  • (一)Java部分 1、列舉出JAVA中6個(gè)比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,071評論 0 62
  • 性格是指人對現(xiàn)實(shí)的態(tài)度和行為方式中比較穩(wěn)定的屋谭、具有核心意義的個(gè)性心理特征脚囊。小學(xué)生正處在性格發(fā)展和初步形成的時(shí)期,一...
    隨遇而安小南北麻麻閱讀 166評論 0 0
  • 這個(gè)世界這么大,干什么不好所意,為什么非要寫作呀淮逊? 這世界這么多人,和誰做盆友不好扶踊,為什么偏偏遇見...
    安非他命rsww閱讀 527評論 4 4