所有知識(shí)點(diǎn)已整理成app
J2EE 部分:
1.Switch能否用string做參數(shù)闯狱?
在 Java 7 之前, switch 只能支持 byte 、 short 屯耸、 char 、 int 或者其對(duì)應(yīng)的封裝類以及 Enum 類型蹭劈。在 Java 7 中疗绣, String 支持被加上了。
延伸(String是基本類型嗎铺韧,可以被繼承嗎)
string是引用類型多矮,底層是char數(shù)組實(shí)現(xiàn)的,string是final類哈打,被在java中被final修飾的類是不可以被繼承的塔逃,所以string不可以被繼承
2. equals與==的區(qū)別:
==是判斷兩個(gè)變量或?qū)嵗遣皇侵赶蛲粋€(gè)內(nèi)存空間 equals是判斷兩個(gè)變量或?qū)嵗赶虻膬?nèi)存空間的值是不是相同
3. Object有哪些公用方法?
- 方法equals測試的是兩個(gè)對(duì)象是否相等
- 方法clone進(jìn)行對(duì)象拷貝
- 方法getClass返回和當(dāng)前對(duì)象相關(guān)的Class對(duì)象
- 方法notify,notifyall,wait都是用來對(duì)給定對(duì)象進(jìn)行線程同步的
5. 實(shí)際開發(fā)中軟引用或者弱引用的使用場景:
1.WeakReference一般用來防止內(nèi)存泄漏料仗,要保證內(nèi)存被虛擬機(jī)回收湾盗,SoftReference多用作來實(shí)現(xiàn)緩存機(jī)制(cache)。
2.SoftReference:軟引用–>如果內(nèi)存空間足夠立轧,垃圾回收器就不會(huì)回收它格粪,如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存氛改。只要垃圾回收器沒有回收它帐萎,該對(duì)象就可以被程序使用。軟引用可用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存胜卤,比如在圖片加載框架中疆导,通過軟引用來實(shí)現(xiàn)內(nèi)存緩存。
3.WeakReference:弱引用–>只具有弱引用的對(duì)象擁有更短暫的生命周期瑰艘。在垃圾回收器線程掃描它 所管轄的內(nèi)存區(qū)域的過程中是鬼,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象肤舞,不管當(dāng)前內(nèi)存空間足夠與否紫新,都會(huì)回收它的內(nèi)存均蜜。不過,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程囤耳, 因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象充择。 Handler 弱引用匪蟀,防止內(nèi)存泄漏。
延伸
到底什么時(shí)候使用軟引用材彪,什么時(shí)候使用弱引用呢段化?
個(gè)人認(rèn)為雄嚣,如果只是想避免OutOfMemory異常的發(fā)生缓升,則可以使用軟引用港谊。如果對(duì)于應(yīng)用的性能更在意,想盡快回收一些占用內(nèi)存比較大的對(duì)象成福,則可以使用弱引用。
還有就是可以根據(jù)對(duì)象是否經(jīng)常使用來判斷蕴潦。如果該對(duì)象可能會(huì)經(jīng)常使用的忽冻,就盡量用軟引用僧诚。如果該對(duì)象不被使用的可能性更大些,就可以用弱引用慈省。
另外,和弱引用功能類似的是WeakHashMap放闺。WeakHashMap對(duì)于一個(gè)給定的鍵,其映射的存在并不阻止垃圾回收器對(duì)該鍵的回收匾寝,回收以后艳悔,其條目從映射中有效地移除。WeakHashMap使用ReferenceQueue實(shí)現(xiàn)的這種機(jī)制乔外。
4.java有幾種數(shù)據(jù)類型
提供了八種基本類型:
- 六種數(shù)字類型(四個(gè)整數(shù)型,兩個(gè)浮點(diǎn)型)
- 字節(jié)型byte 8位 短整型short 16位 整型int 32位 長整型long 64位
- 單精度float 32位 雙精度double 64位
- 一種字符類型
- 字符型char 8位
- 還有一種布爾型四瘫。
- 布爾型:boolean 8位 可存儲(chǔ)"True"和"false"
6. Hashcode的作用找蜜,與 equal 有什么區(qū)別
同樣用于鑒定2個(gè)對(duì)象是否相等的撵孤,java集合中有 list 和 set 兩類裕菠,其中 set不允許元素重復(fù)實(shí)現(xiàn)奴潘,那個(gè)這個(gè)不允許重復(fù)實(shí)現(xiàn)的方法,如果用 equal 去比較的話奈虾,如果存在1000個(gè)元素,你 new 一個(gè)新的元素出來碉纳,需要去調(diào)用1000次 equal 去逐個(gè)和他們比較是否是同一個(gè)對(duì)象,這樣會(huì)大大降低效率铁孵。hashcode實(shí)際上是返回對(duì)象的存儲(chǔ)地址,如果這個(gè)位置上沒有元素鳖擒,就把元素直接存儲(chǔ)在上面蒋荚,如果這個(gè)位置上已經(jīng)存在元素,這個(gè)時(shí)候才去調(diào)用equal方法與新元素進(jìn)行比較,相同的話就不存了容为,散列到其他地址上
7. String、StringBuffer與StringBuilder的區(qū)別
1.String 類型和 StringBuffer 類型的主要性能區(qū)別其實(shí)在于 String 是不可變的對(duì)象
2.StringBuffer和StringBuilder底層是 char[]數(shù)組實(shí)現(xiàn)的 StringBuffer是線程安全的得滤,而StringBuilder是線程不安全的
8. Override和Overload的含義區(qū)別
Overload:1.方法的重載,只在方法之間發(fā)生2.方法名相同,并且區(qū)分大小寫3.參數(shù)列表不同皂股,具體是指參數(shù)的類型,個(gè)數(shù)蘑辑,順序不同4.返回值類型沒有要求,可以相同衔肢,也可以不同
override:1.方法的覆蓋角骤,發(fā)生在父子類之間2.方法名稱,參數(shù)表,返回值都相同疑苫,修飾符一樣或者更寬3.靜態(tài)方法只能被靜態(tài)方法覆蓋撼短,沒有多態(tài)4.子類不能拋出比父類更多的異常<指的是范圍>
9. 抽象類和接口的區(qū)別
一個(gè)類只能繼承單個(gè)類喂柒,但是可以實(shí)現(xiàn)多個(gè)接口 接口強(qiáng)調(diào)特定功能的實(shí)現(xiàn),而抽象類強(qiáng)調(diào)所屬關(guān)系 抽象類中的所有方法并不一定要是抽象的,你可以選擇在抽象類中實(shí)現(xiàn)一些基本的方法昭娩。而接口要求所有的方法都必須是抽象的
10.解析XML的幾種方式的原理與特點(diǎn):DOM、SAX、PULL
- DOM:消耗內(nèi)存:先把xml文檔都讀到內(nèi)存中霎终,然后再用DOM API來訪問樹形結(jié)構(gòu)雁刷,并獲取數(shù)據(jù)。這個(gè)寫起來很簡單,但是很消耗內(nèi)存企蹭。要是數(shù)據(jù)過大翼馆,手機(jī)不夠牛逼只估,可能手機(jī)直接死機(jī)
- SAX:解析效率高爷狈,占用內(nèi)存少,基于事件驅(qū)動(dòng)的:更加簡單地說就是對(duì)文檔進(jìn)行順序掃描,當(dāng)掃描到文檔(document)開始與結(jié)束拷淘、元素(element)開始與結(jié)束贬堵、文檔(document)結(jié)束等地方時(shí)通知事件處理函數(shù)松忍,由事件處理函數(shù)做相應(yīng)動(dòng)作宏所,然后繼續(xù)同樣的掃描,直至文檔結(jié)束霞玄。
- PULL:與 SAX 類似,也是基于事件驅(qū)動(dòng),我們可以調(diào)用它的next()方法风范,來獲取下一個(gè)解析事件(就是開始文檔锌半,結(jié)束文檔,開始標(biāo)簽,結(jié)束標(biāo)簽)遍膜,當(dāng)處于某個(gè)元素時(shí)可以調(diào)用XmlPullParser的getAttributte()方法來獲取屬性的值恩尾,也可調(diào)用它的nextText()獲取本節(jié)點(diǎn)的值。
11.wait()和sleep()的區(qū)別
- sleep來自Thread類,和wait來自O(shè)bject類
- 調(diào)用sleep()方法的過程中,線程不會(huì)釋放對(duì)象鎖堤如。而 調(diào)用 wait 方法線程會(huì)釋放對(duì)象鎖
- sleep睡眠后不出讓系統(tǒng)資源侥猩,wait讓出系統(tǒng)資源其他線程可以占用CPU
- sleep(milliseconds)需要指定一個(gè)睡眠時(shí)間唧取,時(shí)間一到會(huì)自動(dòng)喚醒
12.面向?qū)ο蠖加心男约澳銓?duì)他們的理解
答題技巧
這個(gè)問題沒有標(biāo)準(zhǔn)答案,面試官主要考察的是面試者對(duì)于該問題的理解,因此群凶,面試者在回答這個(gè)問題時(shí)應(yīng)在回答理論后再結(jié)合自己熟悉的例子來說明。
面向?qū)ο?/strong>
繼承:繼承就是從已有類的得到繼承信息創(chuàng)建新類的過程萍虽,提供繼承信息的被稱為父類咆霜,得到繼承信息的被稱為子類
封裝:把數(shù)據(jù)和操作數(shù)據(jù)的方法綁定起來光酣,對(duì)數(shù)據(jù)的訪問只能通過已定義的接口。可以說封裝是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口
多態(tài)性:抽象的來講司致,多態(tài)的意思就是同一消息可以根據(jù)發(fā)送對(duì)象的不同而采用多種不同的行為方式砌庄。(發(fā)送消息就是函數(shù)調(diào)用) 實(shí)現(xiàn)的原理是動(dòng)態(tài)綁定,程序調(diào)用的方法在運(yùn)行期才動(dòng)態(tài)綁定,追溯源碼可以發(fā)現(xiàn)扒俯,JVM 通過參數(shù)的自動(dòng)轉(zhuǎn)型來找到合適的辦法。
抽象:抽象是將一類對(duì)象共同特征總結(jié)出來構(gòu)造類的過程,包括數(shù)據(jù)抽象和行為抽象兩方面废膘。抽象只關(guān)注對(duì)象有哪些屬性和行為孔飒,并不關(guān)注行為的細(xì)節(jié)是什么
理解
面向過程
面向過程就是分析出解決問題的所需要的步驟菩鲜,然后用函數(shù)把這些步驟一步一步實(shí)現(xiàn)狮崩,使用時(shí)依次調(diào)用即可诽凌。例如:一輛汽車用面向過程的思想去考慮它應(yīng)該是這樣的狱窘,如何啟動(dòng)汽車躬络、如何起步提茁、加速火邓、剎車躲胳、熄火等操作摇天,而汽車在這里并不是我們關(guān)心的 內(nèi)容为鳄。
面向?qū)ο?/strong>
面向?qū)ο笫前褬?gòu)成問題的事務(wù)分解成各個(gè)對(duì)象纯丸,建立對(duì)象的目的不是為了完成一個(gè)步驟俊扭,而是為了描述某個(gè)事物在整個(gè)解決問題的步驟中的行為仇矾。例如:一輛汽車用面向?qū)ο蟮乃枷肴?shí)現(xiàn)時(shí)會(huì)以汽車為對(duì)象倾鲫,汽車的發(fā)動(dòng)機(jī)隙疚、傳動(dòng)箱、變速箱、剎車燈屬性是汽車這個(gè)對(duì)象本身所具有的,做任何操作只要控制汽車即可。
13.JAVA多態(tài)的實(shí)現(xiàn)原理
抽象的來講葫男,多態(tài)的意思就是同一消息可以根據(jù)發(fā)送對(duì)象的不同而采用多種不同的行為方式峻呕。(發(fā)送消息就是函數(shù)調(diào)用) 實(shí)現(xiàn)的原理是動(dòng)態(tài)綁定,程序調(diào)用的方法在運(yùn)行期才動(dòng)態(tài)綁定,追溯源碼可以發(fā)現(xiàn),JVM 通過參數(shù)的自動(dòng)轉(zhuǎn)型來找到合適的辦法。
14.JAVA 垃圾回收與內(nèi)存分配策略
14.1 垃圾回收是什么悔详?
就是釋放那些不再持有引用的對(duì)象的內(nèi)存
14.2怎么判斷一個(gè)對(duì)象是否需要收集连锯?
- 什么樣的對(duì)象是垃圾拼弃?
一般來說驳规,所有指向?qū)ο蟮囊枚家咽щ攘玻豢赡茉儆谐绦蚰苷{(diào)用到這個(gè)對(duì)象,那么這個(gè)對(duì)象就成了垃圾吗购,應(yīng)該被回收。
- 什么樣的對(duì)象是垃圾拼弃?
1.1 根據(jù)這個(gè)思路捻勉,很容易就能想到用《引用計(jì)數(shù)》的辦法來確定一個(gè)對(duì)象是否是垃圾镀梭。
即每當(dāng)多一個(gè)引用指向?qū)ο髸r(shí),引用計(jì)數(shù)加一踱启,每當(dāng)少一個(gè)引用指向?qū)ο髸r(shí)报账,引用計(jì)數(shù)減一,引用計(jì)數(shù)減到零埠偿,對(duì)象就可以被回收了透罢。1.2 然而引用計(jì)數(shù)有一個(gè)致命問題不好解決,就是循環(huán)引用的問題冠蒋。
比如說一個(gè)循環(huán)鏈表羽圃,他們循環(huán)引用者,引用計(jì)數(shù)永遠(yuǎn)不會(huì)為零抖剿,但是實(shí)際上程序已經(jīng)不能訪問他們了朽寞,他們應(yīng)該被回收。1.3 所以Java實(shí)際上是使用基于GC Roots的可達(dá)性分析斩郎,什么是GC Roots脑融?
所有類的靜態(tài)變量,每個(gè)線程調(diào)用棧上的本地變量缩宜。(實(shí)際上我們編程時(shí)也是要從這些地方開始訪問數(shù)據(jù))肘迎,所有這些對(duì)象,以及被這些對(duì)象所指向的對(duì)象,都是活的對(duì)象膜宋×蓿活的對(duì)象所指向的對(duì)象也是活的對(duì)象。1.4 所以只要在GC的時(shí)刻秋茫,讓程序暫停運(yùn)行,然后從GC Roots開始分析乃秀,最后沒有被標(biāo)記為活對(duì)象的對(duì)象就是垃圾了肛著。
14.3 Java的四種引用的區(qū)別
- 強(qiáng)引用:如果一個(gè)對(duì)象具有強(qiáng)引用,它就不會(huì)被垃圾回收器回收跺讯。即使當(dāng)前內(nèi)存空間不足枢贿,JVM 也不會(huì)回收它,而是拋出 OutOfMemoryError 錯(cuò)誤刀脏,使程序異常終止局荚。如果想中斷強(qiáng)引用和某個(gè)對(duì)象之間的關(guān)聯(lián),可以顯式地將引用賦值為null愈污,這樣一來的話耀态,JVM在合適的時(shí)間就會(huì)回收該對(duì)象
- 軟引用:在使用軟引用時(shí),如果內(nèi)存的空間足夠暂雹,軟引用就能繼續(xù)被使用首装,而不會(huì)被垃圾回收器回收,只有在內(nèi)存不足時(shí)杭跪,軟引用才會(huì)被垃圾回收器回收仙逻。
- 弱引用:具有弱引用的對(duì)象擁有的生命周期更短暫。因?yàn)楫?dāng) JVM 進(jìn)行垃圾回收涧尿,一旦發(fā)現(xiàn)弱引用對(duì)象系奉,無論當(dāng)前內(nèi)存空間是否充足,都會(huì)將弱引用回收姑廉。不過由于垃圾回收器是一個(gè)優(yōu)先級(jí)較低的線程缺亮,所以并不一定能迅速發(fā)現(xiàn)弱引用對(duì)象
- 虛引用:顧名思義,就是形同虛設(shè)庄蹋,如果一個(gè)對(duì)象僅持有虛引用瞬内,那么它相當(dāng)于沒有引用,在任何時(shí)候都可能被垃圾回收器回收限书。
14.4 介紹垃圾回收機(jī)制
- 標(biāo)記回收法:遍歷對(duì)象圖并且記錄可到達(dá)的對(duì)象虫蝶,以便刪除不可到達(dá)的對(duì)象,一般使用單線程工作并且可能產(chǎn)生內(nèi)存碎片
- 標(biāo)記-壓縮回收法:前期與第一種方法相同倦西,只是多了一步能真,將所有的存活對(duì)象壓縮到內(nèi)存的一端,這樣內(nèi)存碎片就可以合成一大塊可再利用的內(nèi)存區(qū)域,提高了內(nèi)存利用率
- 復(fù)制回收法:把現(xiàn)有內(nèi)存空間分成兩部分粉铐,gc運(yùn)行時(shí)疼约,它把可到達(dá)對(duì)象復(fù)制到另一半空間,再清空正在使用的空間的全部對(duì)象蝙泼。這種方法適用于短生存期的對(duì)象程剥,持續(xù)復(fù)制長生存期的對(duì)象則導(dǎo)致效率降低。
- 分代回收發(fā):把內(nèi)存空間分為兩個(gè)或者多個(gè)域汤踏,如年輕代和老年代织鲸,年輕代的特點(diǎn)是對(duì)象會(huì)很快被回收,因此在年輕代使用效率比較高的算法溪胶。當(dāng)一個(gè)對(duì)象經(jīng)過幾次回收后依然存活搂擦,對(duì)象就會(huì)被放入稱為老年的內(nèi)存空間,老年代則采取標(biāo)記-壓縮算法
14.5 JAVA 中堆和棧的區(qū)別哗脖,說下Java的內(nèi)存機(jī)制瀑踢?
1.基本數(shù)據(jù)類型變量和對(duì)象的引用都是在棧分配的。
2.堆內(nèi)存用來存放由new創(chuàng)建的對(duì)象和數(shù)組才避。
3.類變量(static修飾的變量)橱夭,程序在一加載的時(shí)候就在堆中為類變量分配內(nèi)存,堆中的內(nèi)存地址存放在棧中實(shí)例變量:當(dāng)你使用java關(guān)鍵字new的時(shí)候工扎,系統(tǒng)在堆中開辟并不一定是連續(xù)的空間分配給變量徘钥,是根據(jù)零散的堆內(nèi)存地址,通過哈希算法換算為一長串?dāng)?shù)字以表征這個(gè)變量在堆中的"物理位置”肢娘,實(shí)例變量的生命周期--當(dāng)實(shí)例變量的引用丟失后呈础,將被GC(垃圾回收器)列入可回收“名單”中,但并不是馬上就釋放堆中內(nèi)存橱健。
4.局部變量: 由聲明在某方法而钞,或某代碼段里(比如for循環(huán)),執(zhí)行到它的時(shí)候在棧中開辟內(nèi)存拘荡,當(dāng)局部變量一但脫離作用域臼节,內(nèi)存立即釋放。
- 不同:
1.堆內(nèi)存用來存放由new創(chuàng)建的對(duì)象和數(shù)組珊皿。
2.棧內(nèi)存用來存放方法或者局部變量等
3.堆是先進(jìn)先出网缝,后進(jìn)后出
4.棧是后進(jìn)先出,先進(jìn)后出
- 相同
1.都是屬于Java內(nèi)存的一種
2.系統(tǒng)都會(huì)自動(dòng)去回收它蟋定,但是對(duì)于堆內(nèi)存一般開發(fā)人員會(huì)自動(dòng)回收它
15. Java 集合系列問題
15.1 ArrayList粉臊、LinkedList、Vector的區(qū)別
1驶兜、Vector扼仲、ArrayList都是以類似數(shù)組的形式存儲(chǔ)在內(nèi)存中远寸,LinkedList則以鏈表的形式進(jìn)行存儲(chǔ)。
2屠凶、List中的元素有序驰后、允許有重復(fù)的元素,Set中的元素?zé)o序矗愧、不允許有重復(fù)元素灶芝。
3、Vector線程同步唉韭,ArrayList监署、LinkedList線程不同步。
4纽哥、LinkedList適合指定位置插入、刪除操作栖秕,不適合查找春塌;ArrayList、Vector適合查找簇捍,不適合指定位置的插入只壳、刪除操作。
5暑塑、ArrayList在元素填滿容器時(shí)會(huì)自動(dòng)擴(kuò)充容器大小的50%吼句,而Vector則是100%,因此ArrayList更節(jié)省空間事格。
15.2 HashMap和 HashTable 的區(qū)別
HashTable比較老惕艳,是基于Dictionary 類實(shí)現(xiàn)的,HashMap 則是基于 Map接口實(shí)現(xiàn)的 HashTable 是線程安全的驹愚, HashMap 則是線程不安全的 HashMap可以讓你將空值作為一個(gè)表的條目的key或value
17.什么是反射远搪,在哪里需要用到?
做基礎(chǔ)框架的時(shí)候會(huì)用得上逢捺,一般應(yīng)用層面很少谁鳍,不過這種東西,基本現(xiàn)在很多開源框架都已經(jīng)給封裝好了劫瞳,自己基本用不著寫倘潜。hibernate中用到,但不用自己寫志于。Spring也用到了涮因。經(jīng)典的就是xml或者properties里面寫上了配置,然后在Java類里面解析xml或properties里面的內(nèi)容恨憎,得到一個(gè)字符串蕊退,然后用反射郊楣,根據(jù)這個(gè)字符串獲得某個(gè)類的實(shí)例,這樣就可以動(dòng)態(tài)配置一些東西瓤荔,不用每一次都要在代碼里面去new或者做其他的事情净蚤,以后要改的話直接改配置文件,代碼維護(hù)起來就很方便了输硝,同時(shí)有時(shí)候要適應(yīng)某些需求今瀑,Java類里面不一定能直接調(diào)用另外的方法,這時(shí)候也可以通過反射機(jī)制來實(shí)現(xiàn)点把。
總的來說橘荠,自己寫的很少,具體什么時(shí)候要用那要看需求郎逃,無非就是根據(jù)一個(gè)String來得到你要的實(shí)體對(duì)象哥童,然后調(diào)用它原來的東西。但是如果是要自己寫框架的話褒翰,那就會(huì)用得比較多了贮懈。
18. 什么是線程池,線程池的作用是什么
答:線程池的基本思想還是一種對(duì)象池的思想优训,開辟一塊內(nèi)存空間朵你,里面存放了眾多(未死亡)的線程,池中線程執(zhí)行調(diào)度由池管理器來處理揣非。當(dāng)有線程任務(wù)時(shí)抡医,從池中取一個(gè),執(zhí)行完成后線程對(duì)象歸池早敬,這樣可以避免反復(fù)創(chuàng)建線程對(duì)象所帶來的性能開銷忌傻,節(jié)省了系統(tǒng)的資源。就好比原來去食堂打飯是每個(gè)人看誰搶的贏搁嗓,誰先搶到誰先吃芯勘,有了線程池之后,就是排好隊(duì)形腺逛,今天我跟你關(guān)系好荷愕,你先來吃飯。比如:一個(gè)應(yīng)用要和網(wǎng)絡(luò)打交道棍矛,有很多步驟需要訪問網(wǎng)絡(luò)安疗,為了不阻塞主線程,每個(gè)步驟都創(chuàng)建個(gè)線程够委,在線程中和網(wǎng)絡(luò)交互荐类,用線程池就變的簡單,線程池是對(duì)線程的一種封裝茁帽,讓線程用起來更加簡便玉罐,只需要?jiǎng)?chuàng)一個(gè)線程池屈嗤,把這些步驟像任務(wù)一樣放進(jìn)線程池,在程序銷毀時(shí)只要調(diào)用線程池的銷毀函數(shù)即可吊输。
單個(gè)線程的弊端:a. 每次new Thread新建對(duì)象性能差b. 線程缺乏統(tǒng)一管理饶号,可能無限制新建線程,相互之間競爭季蚂,及可能占用過多系統(tǒng)資源導(dǎo)致死機(jī)或者OOM,c. 缺乏更多功能茫船,如定時(shí)執(zhí)行、定期執(zhí)行扭屁、線程中斷算谈。
java提供的四種線程池的好處在于:a. 重用存在的線程,減少對(duì)象創(chuàng)建料滥、消亡的開銷然眼,性能佳。b. 可有效控制最大并發(fā)線程數(shù)葵腹,提高系統(tǒng)資源的使用率罪治,同時(shí)避免過多資源競爭,避免堵塞礁蔗。c. 提供定時(shí)執(zhí)行、定期執(zhí)行雁社、單線程浴井、并發(fā)數(shù)控制等功能。
2霉撵、Java 線程池
Java通過Executors提供四種線程池磺浙,分別為:
newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池,如果線程池長度超過處理需要徒坡,可靈活回收空閑線程撕氧,若無可回收,則新建線程喇完。
newFixedThreadPool 創(chuàng)建一個(gè)定長線程池伦泥,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待锦溪。
newScheduledThreadPool 創(chuàng)建一個(gè)定長線程池不脯,支持定時(shí)及周期性任務(wù)執(zhí)行。
newSingleThreadExecutor 創(chuàng)建一個(gè)單線程化的線程池诅炉,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù)药磺,保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行躁锡。
5. JNI系列問題
5.1 如何使用JNI
JAVA中聲明native 方法如private native String printJNI(String inputStr);
使用javah工具生成.h頭文件這時(shí)候頭文件中就會(huì)自動(dòng)生成對(duì)應(yīng)的函數(shù)JNIEXPORT jstring JNICALL Java_com_wenming_HelloWorld_printJNI
實(shí)現(xiàn)JNI原生函數(shù)源文件,新建HelloWorld.c文件复局,對(duì)剛才自動(dòng)生成的函數(shù)進(jìn)行具體的邏輯書寫冲簿,例如返回一個(gè)java叫做HelloWorld的字符串等
編譯生成動(dòng)態(tài)鏈接so文件**
Java中調(diào)用Sysytem.load方法把剛才的so庫加載進(jìn)來,就可以調(diào)用native方法了
5.2 如何通過JNI傳遞String對(duì)象
Java的String和C++的string是不能對(duì)等起來的亿昏,所以當(dāng)我們拿到.h文件下面的jstring對(duì)象峦剔,會(huì)做一次轉(zhuǎn)換我們把jstring轉(zhuǎn)換為C下面的char*類型, 獲取值
6. OOM系列問題
6.1 什么OOM龙优?
OOM全稱是Out Of Merrory羊异,Android系統(tǒng)的每一個(gè)應(yīng)用程序都設(shè)置一個(gè)硬性的Dalvik Heap Size最大限制閾值,如果申請(qǐng)的內(nèi)存資源超過這個(gè)限制彤断,系統(tǒng)就會(huì)拋出OOM錯(cuò)誤
6.2 內(nèi)存泄漏有哪些場景以及解決方法
類的靜態(tài)變量持有大數(shù)據(jù)對(duì)象 靜態(tài)變量長期維持到大數(shù)據(jù)對(duì)象的引用野舶,阻止垃圾回收。
非靜態(tài)內(nèi)部類存在靜態(tài)實(shí)例 非靜態(tài)內(nèi)部類會(huì)維持一個(gè)到外部類實(shí)例的引用宰衙,如果非靜態(tài)內(nèi)部類的實(shí)例是靜態(tài)的平道,就會(huì)間接長期維持著外部類的引用,阻止被回收掉供炼。
資源對(duì)象未關(guān)閉 資源性對(duì)象比如(Cursor一屋,F(xiàn)ile文件等)往往都用了一些緩沖,我們?cè)诓皇褂玫臅r(shí)候袋哼,應(yīng)該及時(shí)關(guān)閉它們冀墨, 以便它們的緩沖及時(shí)回收內(nèi)存。它們的緩沖不僅存在于java虛擬機(jī)內(nèi)涛贯,還存在于java虛擬機(jī)外诽嘉。 如果我們僅僅是把它的引用設(shè)置為null,而不關(guān)閉它們,往往會(huì)造成內(nèi)存泄露弟翘。 解決辦法: 比如SQLiteCursor(在析構(gòu)函數(shù)finalize(),如果我們沒有關(guān)閉它虫腋,它自己會(huì)調(diào)close()關(guān)閉), 如果我們沒有關(guān)閉它稀余,系統(tǒng)在回收它時(shí)也會(huì)關(guān)閉它悦冀,但是這樣的效率太低了。 因此對(duì)于資源性對(duì)象在不使用的時(shí)候睛琳,應(yīng)該調(diào)用它的close()函數(shù)盒蟆,將其關(guān)閉掉,然后才置為null. 在我們的程序退出時(shí)一定要確保我們的資源性對(duì)象已經(jīng)關(guān)閉师骗。 程序中經(jīng)常會(huì)進(jìn)行查詢數(shù)據(jù)庫的操作茁影,但是經(jīng)常會(huì)有使用完畢Cursor后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小丧凤, 對(duì)內(nèi)存的消耗不容易被發(fā)現(xiàn)募闲,只有在常時(shí)間大量操作的情況下才會(huì)復(fù)現(xiàn)內(nèi)存問題,這樣就會(huì)給以后的測試和問題排查帶來困難和風(fēng)險(xiǎn)愿待,記得try catch后浩螺,在finally方法中關(guān)閉連接
Handler內(nèi)存泄漏 Handler作為內(nèi)部類存在于Activity中靴患,但是Handler生命周期與Activity生命周期往往并不是相同的,比如當(dāng)Handler對(duì)象有Message在排隊(duì)要出,則無法釋放鸳君,進(jìn)而導(dǎo)致本該釋放的Acitivity也沒有辦法進(jìn)行回收。 解決辦法:
聲明handler為static類患蹂,這樣內(nèi)部類就不再持有外部類的引用了或颊,就不會(huì)阻塞Activity的釋放
-
如果內(nèi)部類實(shí)在需要用到外部類的對(duì)象,可在其內(nèi)部聲明一個(gè)弱引用引用外部類传于。
public class MainActivity extends Activity { private CustomHandler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new CustomHandler(this); } static class CustomHandlerextends Handler { // 內(nèi)部聲明一個(gè)弱引用囱挑,引用外部類 private WeakReference<MainActivity > activityWeakReference; public MyHandler(MyActivity activity) { activityWeakReference= new WeakReference<MainActivity >(activity); } // ... ... } }
-
在Activity onStop或者onDestroy的時(shí)候,取消掉該Handler對(duì)象的Message和Runnable
Override public void onDestroy() { // If null, all callbacks and messages will be removed. mHandler.removeCallbacksAndMessages(null); }
一些不良代碼習(xí)慣 有些代碼并不造成內(nèi)存泄露沼溜,但是他們的資源沒有得到重用平挑,頻繁的申請(qǐng)內(nèi)存和銷毀內(nèi)存,消耗CPU資源的同時(shí)系草,也引起內(nèi)存抖動(dòng) 解決方案 如果需要頻繁的申請(qǐng)內(nèi)存對(duì)象和和釋放對(duì)象通熄,可以考慮使用對(duì)象池來增加對(duì)象的復(fù)用。 例如ListView便是采用這種思想找都,通過復(fù)用converview來避免頻繁的GC
6.2 如何避免 OOM 問題的出現(xiàn)
1. 使用更加輕量的數(shù)據(jù)結(jié)構(gòu) 例如唇辨,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)。通常的HashMap的實(shí)現(xiàn)方式更加消耗內(nèi)存能耻,因?yàn)樗枰粋€(gè)額外的實(shí)例對(duì)象來記錄Mapping操作助泽。另外,SparseArray更加高效嚎京,在于他們避免了對(duì)key與value的自動(dòng)裝箱(autoboxing),并且避免了裝箱后的解箱隐解。
2. 避免在Android里面使用Enum Android官方培訓(xùn)課程提到過“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”鞍帝,具體原理請(qǐng)參考《Android性能優(yōu)化典范(三)》,所以請(qǐng)避免在Android里面使用到枚舉煞茫。
3. 減小Bitmap對(duì)象的內(nèi)存占用 Bitmap是一個(gè)極容易消耗內(nèi)存的大胖子帕涌,減小創(chuàng)建出來的Bitmap的內(nèi)存占用可謂是重中之重,续徽,通常來說有以下2個(gè)措施: inSampleSize:縮放比例蚓曼,在把圖片載入內(nèi)存之前,我們需要先計(jì)算出一個(gè)合適的縮放比例钦扭,避免不必要的大圖載入纫版。 decode format:解碼格式,選擇ARGB_6666/RBG_545/ARGB_4444/ALPHA_6客情,存在很大差異
4.Bitmap對(duì)象的復(fù)用 縮小Bitmap的同時(shí)其弊,也需要提高BitMap對(duì)象的復(fù)用率癞己,避免頻繁創(chuàng)建BitMap對(duì)象,復(fù)用的方法有以下2個(gè)措施 LRUCache : “最近最少使用算法”在Android中有極其普遍的應(yīng)用梭伐。ListView與GridView等顯示大量圖片的控件里痹雅,就是使用LRU的機(jī)制來緩存處理好的Bitmap,把近期最少使用的數(shù)據(jù)從緩存中移除糊识,保留使用最頻繁的數(shù)據(jù)绩社, inBitMap高級(jí)特性:利用inBitmap的高級(jí)特性提高Android系統(tǒng)在Bitmap分配與釋放執(zhí)行效率。使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經(jīng)存在的內(nèi)存區(qū)域赂苗,新解碼的Bitmap會(huì)嘗試去使用之前那張Bitmap在Heap中所占據(jù)的pixel data內(nèi)存區(qū)域愉耙,而不是去問內(nèi)存重新申請(qǐng)一塊區(qū)域來存放Bitmap。利用這種特性哑梳,即使是上千張的圖片劲阎,也只會(huì)僅僅只需要占用屏幕所能夠顯示的圖片數(shù)量的內(nèi)存大小
4. 使用更小的圖片 在涉及給到資源圖片時(shí),我們需要特別留意這張圖片是否存在可以壓縮的空間鸠真,是否可以使用更小的圖片悯仙。盡量使用更小的圖片不僅可以減少內(nèi)存的使用,還能避免出現(xiàn)大量的InflationException吠卷。假設(shè)有一張很大的圖片被XML文件直接引用锡垄,很有可能在初始化視圖時(shí)會(huì)因?yàn)閮?nèi)存不足而發(fā)生InflationException,這個(gè)問題的根本原因其實(shí)是發(fā)生了OOM祭隔。
5.StringBuilder 在有些時(shí)候货岭,代碼中會(huì)需要使用到大量的字符串拼接的操作,這種時(shí)候有必要考慮使用StringBuilder來替代頻繁的“+”疾渴。
4.避免在onDraw方法里面執(zhí)行對(duì)象的創(chuàng)建 類似onDraw等頻繁調(diào)用的方法千贯,一定需要注意避免在這里做創(chuàng)建對(duì)象的操作,因?yàn)樗麜?huì)迅速增加內(nèi)存的使用搞坝,而且很容易引起頻繁的gc搔谴,甚至是內(nèi)存抖動(dòng)。
6. 避免對(duì)象的內(nèi)存泄露 android中內(nèi)存泄漏的場景以及解決辦法桩撮,參考上一問
7. ANR 系列問題
7.1 什么ANR
ANR全稱Application Not Responding敦第,意思就是程序未響應(yīng)。如果一個(gè)應(yīng)用無法響應(yīng)用戶的輸入店量,系統(tǒng)就會(huì)彈出一個(gè)ANR對(duì)話框芜果,用戶可以自行選擇繼續(xù)等待亦或者是停止當(dāng)前程序。一旦出現(xiàn)下面兩種情況融师,則彈出ANR對(duì)話框
- 應(yīng)用在5秒內(nèi)未響應(yīng)用戶的輸入事件(如按鍵或者觸摸)
- BroadcastReceiver未在10秒內(nèi)完成相關(guān)的處理
7.2 ANR是怎么引起的右钾?
- 主線程中存在耗時(shí)的計(jì)算-
- 主線程被IO操作(從4.0之后網(wǎng)絡(luò)IO不允許在主線程中)阻塞。-
- 主線程中錯(cuò)誤的操作,比如Thread.wait或者Thread.sleep等
7.3 如何避免ANR問題的出現(xiàn)
基本思路就是把一些耗時(shí)操作放到子線程中處理
使用AsyncTask處理耗時(shí)IO操作霹粥。
降低子線程優(yōu)先級(jí)使用Thread或者HandlerThread時(shí)灭将,調(diào)用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設(shè)置優(yōu)先級(jí),否則仍然會(huì)降低程序響應(yīng)后控,因?yàn)槟J(rèn)Thread的優(yōu)先級(jí)和主線程相同庙曙。
使用Handler處理子線程結(jié)果,而不是使用Thread.wait()或者Thread.sleep()來阻塞主線程浩淘。
Activity的onCreate和onResume回調(diào)中盡量避免耗時(shí)的代碼
BroadcastReceiver中onReceive代碼也要盡量減少耗時(shí)操作建議使用IntentService處理捌朴。IntentService是一個(gè)異步的,會(huì)自動(dòng)停止的服務(wù)张抄,很好解決了傳統(tǒng)的Service中處理完耗時(shí)操作忘記停止并銷毀Service的問題
8. Asynctask問題
8.1 AsynTask為什么要設(shè)計(jì)為只能夠一次任務(wù)砂蔽?
最核心的還是線程安全問題,多個(gè)子線程同時(shí)運(yùn)行署惯,會(huì)產(chǎn)生狀態(tài)不一致的問題左驾。所以要?jiǎng)?wù)必保證只能夠執(zhí)行一次
8.2 AsynTask造成的內(nèi)存泄露的問題怎么解決
比如非靜態(tài)內(nèi)部類AsynTask會(huì)隱式地持有外部類的引用,如果其生命周期大于外部activity的生命周期极谊,就會(huì)出現(xiàn)內(nèi)存泄漏
- 注意要復(fù)寫AsynTask的onCancel方法诡右,把里面的socket,file等轻猖,該關(guān)掉的要及時(shí)關(guān)掉
- 在 Activity 的onDestory()方法中調(diào)用Asyntask.cancal方法
- Asyntask內(nèi)部使用弱引用的方式來持有Activity
8.3 若Activity已經(jīng)銷毀帆吻,此時(shí)AsynTask執(zhí)行完并且返回結(jié)果,會(huì)報(bào)異常嗎?
當(dāng)一個(gè)App旋轉(zhuǎn)時(shí)咙边,整個(gè)Activity會(huì)被銷毀和重建猜煮。當(dāng)Activity重啟時(shí),AsyncTask中對(duì)該Activity的引用是無效的败许,因此onPostExecute()就不會(huì)起作用王带,若AsynTask正在執(zhí)行,折會(huì)報(bào) view not attached to window manager 異常
同樣也是生命周期的問題市殷,在 Activity 的onDestory()方法中調(diào)用Asyntask.cancal方法愕撰,讓二者的生命周期同步
8.4 Activity銷毀但Task如果沒有銷毀掉,當(dāng)Activity重啟時(shí)這個(gè)AsyncTask該如何解決被丧?
還是屏幕旋轉(zhuǎn)這個(gè)例子,在重建Activity的時(shí)候绪妹,會(huì)回掉Activity.onRetainNonConfigurationInstance()重新傳遞一個(gè)新的對(duì)象給AsyncTask甥桂,完成引用的更新
9. Android觸摸分發(fā)機(jī)制
9.1 介紹觸摸事件的分發(fā)機(jī)制
(1) 事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截邮旷,從最上層的View(ViewGroup)開始一直往下(子View)傳遞黄选。子View可以通過onTouchEvent()對(duì)事件進(jìn)行處理。
(2) 事件由父View(ViewGroup)傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()對(duì)事件做攔截办陷,停止其往下傳遞貌夕。
(3) 如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費(fèi)事件民镜,事件會(huì)反向往上傳遞啡专,這時(shí)父View(ViewGroup)可以進(jìn)行消費(fèi),如果還是沒有被消費(fèi)的話制圈,最后會(huì)到Activity的onTouchEvent()函數(shù)们童。
(4) 如果View沒有對(duì)ACTION_DOWN進(jìn)行消費(fèi),之后的其他事件不會(huì)傳遞過來鲸鹦。
(5) OnTouchListener優(yōu)先于onTouchEvent()對(duì)事件進(jìn)行消費(fèi)慧库。
上面的消費(fèi)即表示相應(yīng)函數(shù)返回值為true。
9.2 View中 setOnTouchListener的onTouch馋嗜,onTouchEvent齐板,onClick的執(zhí)行順序
追溯到View的dispatchTouchEvent源碼查看,有這么一段代碼
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
當(dāng)以下三個(gè)條件任意一個(gè)不成立時(shí)葛菇,
- mOnTouchListener不為null
- view是enable的狀態(tài)
- mOnTouchListener.onTouch(this, event)返回true甘磨,
函數(shù)會(huì)執(zhí)行到onTouchEvent。在這里我們可以看到熟呛,首先執(zhí)行的是mOnTouchListener.onTouch的方法宽档,然后是onTouchEvent方法
繼續(xù)追溯源碼,到onTouchEvent()觀察庵朝,發(fā)現(xiàn)在處理ACTION_UP事件里有這么一段代碼
if (!post(mPerformClick)) {
performClick();
}
此時(shí)可知吗冤,onClick方法也在最后得到了執(zhí)行
所以三者的順序是:
- setOnTouchListener() 的onTouch
- onTouchEvent()
- onClick()
10. Dalvik虛擬機(jī)系列問題
10.1 什么是Dalvik虛擬機(jī)?
Dalvik虛擬機(jī)是Android平臺(tái)的核心九府。它可以支持.dex格式的程序的運(yùn)行椎瘟,.dex格式是專為Dalvik設(shè)計(jì)的一種壓縮格式,可以減少整體文件尺寸侄旬,提高I/O操作的速度肺蔚,適合內(nèi)存和處理器速度有限的系統(tǒng)。
10.2 Dalvik虛擬機(jī)的作用是什么儡羔?
Dalvik虛擬機(jī)主要是完成對(duì)象生命周期管理宣羊,內(nèi)存回收,堆棧管理汰蜘,線程管理仇冯,安全和異常管理等等重要功能。
10.3 Dalvik虛擬機(jī)與JVM有什么區(qū)別
- Dalvik 基于寄存器族操,而 JVM 基于棧苛坚。基于寄存器的虛擬機(jī)對(duì)于更大的程序來說,在它們編譯的時(shí)候泼舱,花費(fèi)的時(shí)間更短等缀。
- Dalvik執(zhí)行.dex格式的字節(jié)碼,而JVM執(zhí)行.class格式的字節(jié)碼娇昙。
10.4 每個(gè)應(yīng)用程序?qū)?yīng)多少個(gè)Dalvik虛擬機(jī)
- 每一個(gè)Android應(yīng)用在底層都會(huì)對(duì)應(yīng)一個(gè)獨(dú)立的Dalvik虛擬機(jī)實(shí)例尺迂,其代碼在虛擬機(jī)的解釋下得以執(zhí)行 ,而所有的Android應(yīng)用的線程都對(duì)應(yīng)一個(gè)Linux線程
11. 注冊(cè)廣播接收器有哪幾種方式,有什么區(qū)別
- 靜態(tài)注冊(cè):在AndroidManifest.xml文件中進(jìn)行注冊(cè)涯贞,當(dāng)App退出后枪狂,Receiver仍然可以接收到廣播并且進(jìn)行相應(yīng)的處理
- 動(dòng)態(tài)注冊(cè):在代碼中動(dòng)態(tài)注冊(cè),當(dāng)App退出后宋渔,也就沒辦法再接受廣播了
12. 顯示Intent與隱式Intent的區(qū)別
對(duì)明確指出了目標(biāo)組件名稱的Intent州疾,我們稱之為“顯式Intent”。 對(duì)于沒有明確指出目標(biāo)組件名稱的Intent皇拣,則稱之為“隱式 Intent”严蓖。
對(duì)于隱式意圖,在定義Activity時(shí)氧急,指定一個(gè)intent-filter颗胡,當(dāng)一個(gè)隱式意圖對(duì)象被一個(gè)意圖過濾器進(jìn)行匹配時(shí),將有三個(gè)方面會(huì)被參考到:
- 動(dòng)作(Action)
- 類別(Category ['k?t?g(?)r?] )
- 數(shù)據(jù)(Data )
14. 不使用動(dòng)畫吩坝,怎么實(shí)現(xiàn)一個(gè)動(dòng)態(tài)的 View毒姨?
1.SurfaceView
2.定時(shí)器或者線程
15. Postvalidata與Validata有什么區(qū)別?
invalidate()得在UI線程中被調(diào)動(dòng)钉寝,在工作者線程中可以通過Handler來通知UI線程進(jìn)行界面更新弧呐。
而postInvalidate()在工作者線程中被調(diào)用
16. 如何自定義ViewGroup?
1.Measure
Measure過程還是測量ViewGroup的大小嵌纲,如果layout_widht和layout_height是match_parent或具體的xxxdp俘枫,就很簡答了,直接調(diào)用setMeasuredDimension()方法逮走,設(shè)置ViewGroup的寬高即可鸠蚪,如果是wrap_content,就比較麻煩了师溅,我們需要遍歷所有的子View茅信,然后對(duì)每個(gè)子View進(jìn)行測量,然后根據(jù)子View的排列規(guī)則墓臭,計(jì)算出最終ViewGroup的大小蘸鲸。
2.onLayout來按照我們想要的規(guī)則自定義子View排列。
3.ViewGroup在draw階段起便,其實(shí)就是按照子類的排列順序棚贾,調(diào)用子類的onDraw方法,因?yàn)槲覀冎皇荲iew的容器榆综, 本身一般不需要draw額外的修飾妙痹,所以往往在onDraw方法里面,只需要調(diào)用ViewGroup的onDraw默認(rèn)實(shí)現(xiàn)方法即可鼻疮。
17. View的繪制流程
measure()方法怯伊,layout(),draw()三個(gè)方法主要存放了一些標(biāo)識(shí)符判沟,來判斷每個(gè)View是否需要再重新測量耿芹,布局或者繪制,主要的繪制過程還是在onMeasure挪哄,onLayout吧秕,onDraw這個(gè)三個(gè)方法中
1.onMesarue() 為整個(gè)View樹計(jì)算實(shí)際的大小,即設(shè)置實(shí)際的高(對(duì)應(yīng)屬性:mMeasuredHeight)和寬(對(duì)應(yīng)屬性: mMeasureWidth)迹炼,每個(gè)View的控件的實(shí)際寬高都是由父視圖和本身視圖決定的砸彬。
2.onLayout() 為將整個(gè)根據(jù)子視圖的大小以及布局參數(shù)將View樹放到合適的位置上。
3. onDraw() 開始繪制圖像斯入,繪制的流程如下
- 首先繪制該View的背景
- 調(diào)用onDraw()方法繪制視圖本身 (每個(gè)View都需要重載該方法砂碉,ViewGroup不需要實(shí)現(xiàn)該方法)
- 如果該View是ViewGroup,調(diào)用dispatchDraw ()方法繪制子視圖
- 繪制滾動(dòng)條
18. 數(shù)據(jù)持久化的四種方式有哪些刻两?
文件存儲(chǔ): 通過java.io.FileInputStream和java.io.FileOutputStream這兩個(gè)類來實(shí)現(xiàn)對(duì)文件的讀寫增蹭,java.io.File類則用來構(gòu)造一個(gè)具體指向某個(gè)文件或者文件夾的對(duì)象。
SharedPreferences: SharedPreferences是一種輕量級(jí)的數(shù)據(jù)存儲(chǔ)機(jī)制磅摹,他將一些簡單的數(shù)據(jù)類型的數(shù)據(jù)滋迈,包括boolean類型,int類型偏瓤,float類型杀怠,long類型以及String類型的數(shù)據(jù),以鍵值對(duì)的形式存儲(chǔ)在應(yīng)用程序的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中厅克,這種Preferences機(jī)制廣泛應(yīng)用于存儲(chǔ)應(yīng)用程序中的配置信息赔退。
SQLite數(shù)據(jù)庫: 當(dāng)應(yīng)用程序需要處理的數(shù)據(jù)量比較大時(shí),為了更加合理地存儲(chǔ)证舟、管理硕旗、查詢數(shù)據(jù),我們往往使用關(guān)系數(shù)據(jù)庫來存儲(chǔ)數(shù)據(jù)女责。Android系統(tǒng)的很多用戶數(shù)據(jù)漆枚,如聯(lián)系人信息,通話記錄抵知,短信息等墙基,都是存儲(chǔ)在SQLite數(shù)據(jù)庫當(dāng)中的软族,所以利用操作SQLite數(shù)據(jù)庫的API可以同樣方便的訪問和修改這些數(shù)據(jù)。
ContentProvider: 主要用于在不同的應(yīng)用程序之間實(shí)現(xiàn)數(shù)據(jù)共享的功能残制,不同于sharepreference和文件存儲(chǔ)中的兩種全局可讀寫操作模式立砸,內(nèi)容提供其可以選擇只對(duì)哪一部分?jǐn)?shù)據(jù)進(jìn)行共享,從而保證我們程序中的隱私數(shù)據(jù)不會(huì)有泄漏的風(fēng)險(xiǎn)
19. fragement里面可以再嵌套fragment初茶?
20. Socker編程的步驟
21. Activity中如何動(dòng)態(tài)的添加Fragment
22. Scrollview怎么判斷是否滑倒底部
1.通過OnTouchListener來監(jiān)聽滑動(dòng)颗祝,如果getChildAt(0)不為空且view的高度小于等于 getScrollY() + getHeight()為底部
2.同理重寫ScrollView的onScrollChanged的方法,在onScrollChanged函數(shù)中判斷
23. 什么是 MVC 模式恼布?MVC 模式的好處是什么螺戳?
MVC的具體含義是:model+view+control,即模型+視圖+控制它們各自處理自己的任務(wù)
(1)一個(gè)模型提供不同的多個(gè)視圖表現(xiàn)形式折汞,也能夠?yàn)橐粋€(gè)模型創(chuàng)建新的視圖而無須重寫模型倔幼。一旦模型的數(shù)據(jù)發(fā)生變化,模型將通知有關(guān)的視圖爽待,每個(gè)視圖相應(yīng)地刷新自己凤藏。
(2)模型可復(fù)用。因?yàn)槟P褪仟?dú)立于視圖的堕伪,所以可以把一個(gè)模型獨(dú)立地移植到新的平臺(tái)工作揖庄。
(3)提高開發(fā)效率。在開發(fā)界面顯示部分時(shí)欠雌,你僅僅需要考慮的是如何布局一個(gè)好的用戶界面蹄梢;開發(fā)模型時(shí),你僅僅要考慮的是業(yè)務(wù)邏輯和數(shù)據(jù)維護(hù)富俄,這樣能使開發(fā)者專注于某一方面的開發(fā)禁炒,提高開發(fā)效率。
24. 應(yīng)用常駐后臺(tái)霍比,避免被第三方殺掉的方法幕袱,講講你用過的奇淫巧技?
Service設(shè)置成START_STICKY kill 后會(huì)被重啟(等待5秒左右)悠瞬,重傳Intent们豌,保持與重啟前一樣
通過 startForeground將進(jìn)程設(shè)置為前臺(tái)進(jìn)程蚜点, 做前臺(tái)服務(wù)罩阵,優(yōu)先級(jí)和前臺(tái)應(yīng)用一個(gè)級(jí)別?,除非在系統(tǒng)內(nèi)存非常缺桐智,否則此進(jìn)程不會(huì)被 kill
雙進(jìn)程Service: 讓2個(gè)進(jìn)程互相保護(hù)**凌外,其中一個(gè)Service被清理后辩尊,另外沒被清理的進(jìn)程可以立即重啟進(jìn)程
QQ黑科技: 在應(yīng)用退到后臺(tái)后,另起一個(gè)只有 1 像素的頁面停留在桌面上康辑,讓自己保持前臺(tái)狀態(tài)摄欲,保護(hù)自己不被后臺(tái)清理工具殺死
在已經(jīng)root的設(shè)備下轿亮,修改相應(yīng)的權(quán)限文件,將App偽裝成系統(tǒng)級(jí)的應(yīng)用 Android4.0系列的一個(gè)漏洞,已經(jīng)確認(rèn)可行
用C編寫守護(hù)進(jìn)程(即子進(jìn)程) : Android系統(tǒng)中當(dāng)前進(jìn)程(Process)fork出來的子進(jìn)程胸墙,被系統(tǒng)認(rèn)為是兩個(gè)不同的進(jìn)程哀托。當(dāng)父進(jìn)程被殺死的時(shí)候,子進(jìn)程仍然可以存活劳秋,并不受影響。鑒于目前提到的在Android->- Service層做雙守護(hù)都會(huì)失敗胖齐,我們可以fork出c進(jìn)程玻淑,多進(jìn)程守護(hù)。死循環(huán)在那檢查是否還存在呀伙,具體的思路如下(Android5.0以上的版本不可行)
用C編寫守護(hù)進(jìn)程(即子進(jìn)程)补履,守護(hù)進(jìn)程做的事情就是循環(huán)檢查目標(biāo)進(jìn)程是否存在,不存在則啟動(dòng)它剿另。
在NDK環(huán)境中將1中編寫的C代碼編譯打包成可執(zhí)行文件(BUILD_EXECUTABLE)箫锤。主進(jìn)程啟動(dòng)時(shí)將守護(hù)進(jìn)程放入私有目錄下,賦予可執(zhí)行權(quán)限雨女,啟動(dòng)它即可谚攒。
聯(lián)系廠商,加入白名單
25.Context與ApplicationContext的區(qū)別氛堕,分別用在什么情況下
Application的Context是一個(gè)全局靜態(tài)變量馏臭,SDK的說明是只有當(dāng)你引用這個(gè)context的生命周期超過了當(dāng)前activity的生命周期,而和整個(gè)應(yīng)用的生命周期掛鉤時(shí)讼稚,才去使用這個(gè)application的context括儒。
在android中context可以作很多操作,但是最主要的功能是加載和訪問資源锐想。在android中有兩種context帮寻,一種是 application context,一種是activity context赠摇,通常我們?cè)诟鞣N類和方法間傳遞的是activity context固逗。
26. 同一個(gè)應(yīng)用程序的不同Activity可以運(yùn)行在不同的進(jìn)程中么?如果可以藕帜,舉例說明抒蚜;
27. Java中的線程同步有哪幾種方式,舉例說明耘戚;
28. dp, dip, dpi, px, sp是什么意思以及他們的換算公式嗡髓?layout-sw400dp, layout-h400dp分別代表什么意思;
29. 如何讓兩個(gè)TextView在一個(gè)RelativeLayout水平居中顯示收津;
30. 如何畫出一個(gè)印章的圖案
31. 如何實(shí)現(xiàn)一個(gè)字體的描邊與陰影效果
32. 設(shè)計(jì)一個(gè)從網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)饿这,圖片浊伙,并加載到列表的系統(tǒng),畫出客戶端架構(gòu)并簡單的分析下长捧;
33. 設(shè)計(jì)一個(gè)文件的斷點(diǎn)續(xù)傳系統(tǒng)嚣鄙;
34. 設(shè)計(jì)一個(gè)圖片緩存加載機(jī)制
數(shù)據(jù)結(jié)構(gòu)與算法部分:
- 給最外層的rootview,把這個(gè)根視圖下的全部button背景設(shè)置成紅色串结,手寫代碼哑子,不許用遞歸
- 給一串字符串比如abbbcccd,輸出a1b3c3d1肌割,手寫代碼(注意有個(gè)別字符可能會(huì)出現(xiàn)十次以上的情況)
- 一個(gè)序列卧蜓,它的形式是12349678,9是最高峰把敞,經(jīng)歷了一個(gè)上升又下降的過程弥奸,找出里面的最大值的位置,要求效率盡可能高
- 二叉查找樹的刪除操作奋早,手寫代碼
- 反轉(zhuǎn)鏈表盛霎,手寫代碼
- 二分查找,手寫代碼
- 有海量條 url耽装,其中不重復(fù)的有300萬條愤炸,現(xiàn)在希望挑選出重復(fù)出現(xiàn)次數(shù)最高的 url,要求效率盡可能的高
- 一篇英語文章掉奄,去掉字符只留下k個(gè)摇幻,如何去掉才能使這k個(gè)字符字典序最小
- 弗洛伊德算法和 Dijkstra算法的區(qū)別?復(fù)雜度是多少挥萌?講講 Dijkstra算法的具體過程
- 反轉(zhuǎn)字符串绰姻,要求手寫代碼,優(yōu)化速度引瀑、優(yōu)化空間
- 給出兩個(gè)無向圖狂芋,找出這2個(gè)無向圖中相同的環(huán)路。手寫代碼
- 單例模式憨栽,手寫代碼
- 生產(chǎn)者與消費(fèi)者帜矾,手寫代碼
- 二叉樹鏡像,手寫代碼
- 最長不重復(fù)子串(最長重復(fù)子串)屑柔,手寫代碼
操作系統(tǒng)部分:
- 分別從操作系統(tǒng)的內(nèi)存角度與進(jìn)程線程角度解釋分析堆屡萤,棧二者的區(qū)別
- 什么是事務(wù)?
- OSI七層模型有哪些掸宛,各層次的作用
- TCP的三次握手過程死陆,四次揮手過程,為什么需要三次?
- 說說操作系統(tǒng)中進(jìn)程的通信方式
- 瀏覽器輸入地址之后措译,之后的過程
- 談?wù)?HTTP 中Get 和 Post 方法的區(qū)別别凤?
如何將一個(gè)java對(duì)象序列化到文件里
在java中能夠被序列化的類必須先實(shí)現(xiàn)Serializable接口,該接口沒有任何抽象方法只是起到一個(gè)標(biāo)記作用领虹。
// 創(chuàng)建一個(gè)User對(duì)象
User user = new User();
user.setId(1);
user.setName("Mr XP.Wang");
// 創(chuàng)建一個(gè)List對(duì)象
List<String> list = new ArrayList<String>();
list.add("My name");
list.add(" is");
list.add(" Mr XP.Wang");
try {
ObjectOutputStream os = new ObjectOutputStream(
new FileOutputStream("C:/wxp.txt"));
os.writeObject(user);// 將User對(duì)象寫進(jìn)文件
os.writeObject(list);// 將List列表寫進(jìn)文件
os.close();
...
讀取
ObjectInputStream is = new ObjectInputStream(new FileInputStream(
"C:/wxp.txt"));
User temp = (User) is.readObject();// 從流中讀取User的數(shù)據(jù)
System.out.println(temp.getId());
System.out.println(temp.getName());
List tempList = (List) is.readObject();// 從流中讀取List的數(shù)據(jù)
for (Iterator iterator = tempList.iterator(); iterator.hasNext();) {
System.out.print(iterator.next());
}
is.close();
線程池的啟動(dòng)策略
線程池的啟動(dòng)策略
線程池剛創(chuàng)建時(shí)规哪,里面沒有一個(gè)線程。任務(wù)隊(duì)列是作為參數(shù)傳進(jìn)來的塌衰。不過诉稍,就算隊(duì)列里面有任務(wù),線程池也不會(huì)馬上執(zhí)行它們最疆。
當(dāng)調(diào)用execute() 方法添加一個(gè)任務(wù)時(shí)杯巨,線程池會(huì)做如下判斷:
如果正在運(yùn)行的線程數(shù)量小于 corePoolSize,那么馬上創(chuàng)建線程運(yùn)行這個(gè)任務(wù)肚菠;
當(dāng)一個(gè)線程完成任務(wù)時(shí),它會(huì)從隊(duì)列中取下一個(gè)任務(wù)來執(zhí)行罩缴。
當(dāng)一個(gè)線程無事可做蚊逢,超過一定的時(shí)間(keepAliveTime)時(shí),線程池會(huì)判斷箫章,如果當(dāng)前運(yùn)行的線程數(shù)大于 corePoolSize烙荷,那么這個(gè)線程就被停掉。所以線程池的所有任務(wù)完成后檬寂,它最終會(huì)收縮到 corePoolSize 的大小终抽。
抽象與封裝有何區(qū)別
答案說明
抽象是從眾多的事物中抽取共同的、本質(zhì)性的特征桶至,而舍棄其非本質(zhì)的特征昼伴。封裝則是將抽象得到的數(shù)據(jù)和行為(或功能)相結(jié)合,形成一個(gè)有機(jī)的整體镣屹,也就是將數(shù)據(jù)與操作數(shù)據(jù)的源代碼進(jìn)行有機(jī)的結(jié)合圃郊,形成“類”,其中數(shù)據(jù)和函數(shù)都是類的成員女蜈。抽象是更通用的術(shù)語持舆,它的實(shí)現(xiàn)可以由子類完成。例如伪窖,List類是一種JavaSE抽象逸寓,List的具體子類ArrayList和LinkedList。如果沒有通過封裝隱藏其內(nèi)部狀態(tài)覆山,抽象也不可能實(shí)現(xiàn)竹伸,如果一個(gè)類暴露其內(nèi)部狀態(tài),它不能在其內(nèi)部完全掌控改變這個(gè)狀態(tài)簇宽,那么這也不是抽象佩伤。封裝是作為抽象的一部分聊倔。封裝是對(duì)象封裝它自己的狀態(tài),并對(duì)外部隱藏生巡,該類以外的其他類必須通過它的方法進(jìn)行交互耙蔑,但不能直接訪問該類的狀態(tài)。所以封裝的類是為抽象了有關(guān)其狀態(tài)的實(shí)現(xiàn)細(xì)節(jié)孤荣。
談一談JVM的內(nèi)存結(jié)構(gòu)和內(nèi)存分配
Java內(nèi)存模型
- Java虛擬機(jī)將其管轄的內(nèi)存大致分三個(gè)邏輯部分:方法區(qū)(Method Area)甸陌、Java棧和Java堆。
- 方法區(qū)是靜態(tài)分配的盐股,編譯器將變量綁定在某個(gè)存儲(chǔ)位置上钱豁,而且這些綁定不會(huì)在運(yùn)行時(shí)改變。
- Java Stack是一個(gè)邏輯概念疯汁,特點(diǎn)是后進(jìn)先出牲尺。一個(gè)棧的空間可能是連續(xù)的,也可能是不連續(xù)的幌蚊。
- Java堆分配(heap allocation)意味著以隨意的順序谤碳,在運(yùn)行時(shí)進(jìn)行存儲(chǔ)空間分配和收回的內(nèi)存管理模型。
java內(nèi)存分配
- 基礎(chǔ)數(shù)據(jù)類型直接在椧缍梗空間分配;
- 方法的形式參數(shù)蜒简,直接在棧空間分配漩仙,當(dāng)方法調(diào)用完成后從棿瓴纾空間回收;
- 引用數(shù)據(jù)類型,需要用new來創(chuàng)建队他,既在椌砺兀空間分配一個(gè)地址空間,又在堆空間分配對(duì)象的類變量;
- 方法的引用參數(shù)麸折,在椣登梗空間分配一個(gè)地址空間,并指向堆空間的對(duì)象區(qū)磕谅,當(dāng)方法調(diào)用完后從椝揭空間回收;
- 局部變量 new 出來時(shí),在棽布校空間和堆空間中分配空間衬浑,當(dāng)局部變量生命周期結(jié)束后,椃排伲空間立刻被回收工秩,堆空間區(qū)域等待GC回收;
- 方法調(diào)用時(shí)傳入的實(shí)際參數(shù),先在棧空間分配助币,在方法調(diào)用完成后從椑颂空間釋放;
字符串常量在 DATA 區(qū)域分配 ,this 在堆空間分配; - 數(shù)組既在椕剂猓空間分配數(shù)組名稱迹栓, 又在堆空間分配數(shù)組實(shí)際的大小俭缓!
Java的類加載器的種類都有哪些
加載器種類
根類加載器(Bootstrap) --C++寫的 克伊,看不到源碼。擴(kuò)展類加載器(Extension) --加載位置 :jrelibext中华坦。系統(tǒng)(應(yīng)用)類加載器(SystemApp) --加載位置 :classpath中愿吹。自定義加載器(必須繼承ClassLoader)。
什么是值傳遞和引用傳遞
對(duì)象被值傳遞惜姐,意味著傳遞了對(duì)象的一個(gè)副本犁跪。因此,就算是改變了對(duì)象副本歹袁,也不會(huì)影響原對(duì)象的值
同步方法和同步代碼塊的區(qū)別是什么
在java語言中坷衍,每一個(gè)對(duì)象有一把鎖。線程可以使用synchronized關(guān)鍵字來獲取對(duì)象上的鎖宇攻。synchronized關(guān)鍵字可應(yīng)用在方法級(jí)別(粗粒度鎖)或者是代碼塊級(jí)別(細(xì)粒度鎖)惫叛。
多線程有什么弊端
1.降低了一個(gè)進(jìn)程里面的線程的執(zhí)行頻率倡勇。
2.對(duì)線程進(jìn)行管理要求額外的 CPU開銷逞刷。
3.線程的使用會(huì)給系統(tǒng)帶來上下文切換的額外負(fù)擔(dān)。
4.公有變量的同時(shí)讀或?qū)懫扌堋.?dāng)多個(gè)線程需要對(duì)公有變量進(jìn)行寫操作時(shí)夸浅,后一個(gè)線程往往會(huì)修改掉前一個(gè)線程存放的數(shù)據(jù),發(fā)生線程安全問題扔役。
5.線程的死鎖帆喇。即較長時(shí)間的等待或資源競爭以及死鎖等多線程癥狀。
實(shí)現(xiàn)接口方式和繼承方式有什么區(qū)別
1.Java中是不允許類實(shí)現(xiàn)多繼承的亿胸,但是如果一個(gè)A類中有一部分代碼需要多線程執(zhí)行坯钦,采用第一種方法實(shí)現(xiàn)的話,就繼承了Thread類侈玄,不能再繼續(xù)繼承其他類婉刀,限制了A類功能的擴(kuò)展。
2.Java已經(jīng)考慮到這種情況序仙,采用第二種實(shí)現(xiàn)多線程的方法的話突颊,既可以在繼承其他功能類的同時(shí),可以通過實(shí)現(xiàn)接口的方法實(shí)現(xiàn)多線程。
3.實(shí)現(xiàn)接口的好處:避免了單繼承的局限性律秃。
抽象類可以沒有抽象方法嗎爬橡?
抽象類可以沒有抽象方法,但是這樣的抽象類無實(shí)際使用意義棒动,除非是想要一個(gè)類不能被直接實(shí)例化糙申,則可以定義為無抽象方法的抽象類
iterator和Listiterator的區(qū)別是什么
1.Iterator可用來遍歷Set和ListJavaSE,但是ListIterator只能用來遍歷List迁客。
2.Iterator對(duì)JavaSE只能是前向遍歷郭宝,ListIterator既可以前向也可以后向。
3.ListIterator實(shí)現(xiàn)了Iterator接口掷漱,并包含其他的功能粘室,比如:增加元素,替換元素卜范,獲取前一個(gè)和后一個(gè)元素的索引衔统,等等。
Java中Exception和Error有什么區(qū)別
Exception和Error都是Throwable的子類海雪。Exception用于用戶程序可以捕獲的異常情況锦爵。Error是錯(cuò)誤,不能被用戶程序捕獲奥裸。
Java中什么是構(gòu)造函數(shù)险掀?什么是構(gòu)造函數(shù)重載?什么是復(fù)制構(gòu)造函數(shù)湾宙?
- 1.當(dāng)新對(duì)象被創(chuàng)建的時(shí)候樟氢,構(gòu)造函數(shù)會(huì)被調(diào)用。每一個(gè)類都有構(gòu)造函數(shù)侠鳄。在程序員沒有給類提供構(gòu)造函數(shù)的情況下埠啃,Java編譯器會(huì)為這個(gè)類創(chuàng)建一個(gè)默認(rèn)的構(gòu)造函數(shù)。
- 2.Java中構(gòu)造函數(shù)重載和方法重載很相似伟恶〔昕可以為一個(gè)類創(chuàng)建多個(gè)構(gòu)造函數(shù)。每一個(gè)構(gòu)造函數(shù)必須有它自己唯一的參數(shù)列表博秫。
- 3.Java不支持像C++中那樣的復(fù)制構(gòu)造函數(shù)潦牛,這個(gè)不同點(diǎn)是因?yàn)槿绻悴蛔约簩憳?gòu)造函數(shù)的情況下,Java不會(huì)創(chuàng)建默認(rèn)的復(fù)制構(gòu)造函數(shù)挡育。
java中有幾種類型的流巴碗?JDK為每種類型的流提供了一些抽象類以供繼承,請(qǐng)說出他們分別是哪些類静盅?
字節(jié)流良价,字符流寝殴。字節(jié)流繼承于InputStream OutputStream,字符流繼承于InputStreamReaderOutputStreamWriter明垢。在java.io包中還有許多其他的流蚣常,主要是為了提高性能和使用方便。
Serializable和Parcelable的區(qū)別?
1.在使用內(nèi)存的時(shí)候痊银,Parcelable 類比Serializable性能高抵蚊,所以推薦使用Parcelable類。
2.Serializable在序列化的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量溯革,從而引起頻繁的GC贞绳。
3.Parcelable不能使用在要將數(shù)據(jù)存儲(chǔ)在磁盤上的情況。盡管Serializable效率低點(diǎn)致稀,但在這種情況下冈闭,還是建議你用Serializable 。
4.Serializable 的實(shí)現(xiàn)抖单,只需要繼承Serializable 即可萎攒。這只是給對(duì)象打了一個(gè)標(biāo)記,系統(tǒng)會(huì)自動(dòng)將其序列化矛绘。
5.Parcelabel 的實(shí)現(xiàn)耍休,需要在類中添加一個(gè)靜態(tài)成員變量 CREATOR,這個(gè)變量需要繼承 Parcelable.Creator 接口货矮。
說說你對(duì)線程池的理解
答案解析:
使用線程池的原因:
- 1.減少了創(chuàng)建和銷毀線程的次數(shù)羊精,每個(gè)工作線程都可以被重復(fù)利用,可執(zhí)行多個(gè)任務(wù)囚玫。
- 2.可以根據(jù)系統(tǒng)的承受能力喧锦,調(diào)整線程池中工作線線程的數(shù)目,防止因?yàn)橄倪^多的內(nèi)存劫灶,(每個(gè)線程需要大約1MB內(nèi)存裸违,線程開的越多掖桦,消耗的內(nèi)存也就越大)本昏。
線程池的分類:
- 1.線程池都是通過Executors來創(chuàng)建的。
- 2.newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池枪汪,如果線程池長度超過處理需要涌穆,可靈活回收空閑線程,若無可回收雀久,則新建線程宿稀。
- 3.newFixedThreadPool 創(chuàng)建一個(gè)定長線程池,可控制線程最大并發(fā)數(shù)赖捌,超出的線程會(huì)在隊(duì)列中等待祝沸。
- 4.newScheduledThreadPool 創(chuàng)建一個(gè)定長線程池矮烹,支持定時(shí)及周期性任務(wù)執(zhí)行。
- 5.newSingleThreadExecutor 創(chuàng)建一個(gè)單線程化的線程池罩锐,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù)奉狈,保證所有任務(wù)按照指定順序執(zhí)行。
線程數(shù)解析:
- 1.corePoolSize: 線程池維護(hù)線程的最少數(shù)量涩惑。
- 2.maximumPoolSize:線程池維護(hù)線程的最大數(shù)量仁期。
- 3.keepAliveTime: 線程池維護(hù)線程所允許的空閑時(shí)間。
- 4.workQueue: 線程池所使用的緩沖隊(duì)列竭恬。
- 5.handler: 線程池對(duì)拒絕任務(wù)的處理策略跛蛋。
創(chuàng)建規(guī)則:
一個(gè)任務(wù)通過execute(Runnable)方法欲添加到線程池時(shí):
- 1.如果此時(shí)線程池中的數(shù)量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài)痊硕,也要?jiǎng)?chuàng)建新的線程來處理被添加的任務(wù)赊级。
- 2.如果此時(shí)線程池中的數(shù)量等于 corePoolSize,但是緩沖隊(duì)列 workQueue未滿岔绸,那么任務(wù)被放入緩沖隊(duì)列此衅。
- 3.如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿亭螟,并且線程池中的數(shù)量小于maximumPoolSize挡鞍,建新的線程來處理被添加的任務(wù)。
- 4.如果此時(shí)線程池中的數(shù)量大于corePoolSize预烙,緩沖隊(duì)列workQueue滿墨微,并且線程池中的數(shù)量等于maximumPoolSize,那么通過 handler所指定的策略來處理此任務(wù)扁掸。也就是:處理任務(wù)的優(yōu)先級(jí)為:核心線程corePoolSize翘县、任務(wù)隊(duì)列workQueue、最大線程maximumPoolSize谴分,如果三者都滿了锈麸,使用handler處理被拒絕的任務(wù)。
- 5.當(dāng)線程池中的線程數(shù)量大于 corePoolSize時(shí)牺蹄,如果某線程空閑時(shí)間超過keepAliveTime忘伞,線程將被終止。這樣沙兰,線程池可以動(dòng)態(tài)的調(diào)整池中的線程數(shù)氓奈。
終止和關(guān)閉線程池:
hreadPoolExecutor提供了兩個(gè)方法,用于線程池的關(guān)閉鼎天,分別是shutdown()和shutdownNow()舀奶,其中:
- 1.Shutdown():不會(huì)立即終止線程池,而是要等所有任務(wù)緩存隊(duì)列中的任務(wù)都執(zhí)行完后才終止斋射,但再也不會(huì)接受新的任務(wù)育勺。
- 2.ShutdownNow():立即終止線程池但荤,并嘗試打斷正在執(zhí)行的任務(wù),并且清空任務(wù)緩存隊(duì)列涧至,返回尚未執(zhí)行的任務(wù)纱兑。
Java中實(shí)現(xiàn)多態(tài)的機(jī)制是什么?
靠的是父類或接口定義的引用變量可以指向子類或具體實(shí)現(xiàn)類的實(shí)例對(duì)象化借,而程序調(diào)用的方法在運(yùn)行期才動(dòng)態(tài)綁定潜慎,就是引用變量所指向的具體實(shí)例對(duì)象的方法,也就是內(nèi)存里正在運(yùn)行的那個(gè)對(duì)象的方法蓖康,而不是引用變量的類型中定義的方法铐炫。
描述一下JVM加載class文件的原理機(jī)制?
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)生與所加載類對(duì)應(yīng)的Class對(duì)象邪意。加載完成后九妈,Class對(duì)象還不完整,所以此時(shí)的類還不可用雾鬼。當(dāng)類被加載后就進(jìn)入連接階段萌朱,這一階段包括驗(yàn)證箭券、準(zhǔn)備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認(rèn)的初始值)和解析(將符號(hào)引用替換為直接引用)三個(gè)步驟改艇。最后JVM對(duì)類進(jìn)行初始化咐扭,包括:
- 1.如果類存在直接的父類并且這個(gè)類還沒有被初始化奕筐,那么就先初始化父類。
- 2.如果類中存在初始化語句赎线,就依次執(zhí)行這些初始化語句缔御。
- 3.類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)竟块、擴(kuò)展加載器(Extension)、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)耐齐。
- 從Java 2(JDK 1.2)開始浪秘,類加載過程采取了父親委托機(jī)制(PDM)蒋情。PDM更好的保證了Java平臺(tái)的安全性,在該機(jī)制中耸携,JVM自帶的Bootstrap是根加載器棵癣,其他的加載器都有且僅有一個(gè)父類加載器。類的加載首先請(qǐng)求父類加載器加載夺衍,父類加載器無能為力時(shí)才由其子類加載器自行加載狈谊。
- JVM不會(huì)向Java程序提供對(duì)Bootstrap的引用。下面是關(guān)于幾個(gè)類加載器的說明:
- 1.Bootstrap:一般用本地代碼實(shí)現(xiàn)沟沙,負(fù)責(zé)加載JVM基礎(chǔ)核心類庫(rt.jar)河劝。
- 2.Extension:從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫,它的父加載器是Bootstrap矛紫。
- 3.System:又叫應(yīng)用類加載器赎瞎,其父類是Extension。它是應(yīng)用最廣泛的類加載器颊咬。它從環(huán)境變量classpath或者系統(tǒng)屬性 java.class.path所指定的目錄中記載類务甥,是用戶自定義加載器的默認(rèn)父加載器。
finalize()方法什么時(shí)候被調(diào)用喳篇?析構(gòu)函數(shù)(finalization)的目的是什么敞临?
在釋放對(duì)象占用的內(nèi)存之前,垃圾收集器會(huì)調(diào)用對(duì)象的finalize()方法麸澜。一般建議在該方法中釋放對(duì)象持有的資源哟绊。
在釋放對(duì)象占用的內(nèi)存之前,垃圾收集器會(huì)調(diào)用對(duì)象的finalize()方法痰憎。一般建議在該方法中釋放對(duì)象持有的資源票髓。
不會(huì),在下一個(gè)垃圾回收周期中铣耘,這個(gè)對(duì)象將是可被回收的洽沟。
GC是什么? 為什么要有GC?
答案解析:
GC是垃圾收集的意思(Gabage Collection),內(nèi)存處理是編程人員容易出現(xiàn)問題的地方蜗细,忘記或者錯(cuò)誤的內(nèi)存回收會(huì)導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰裆操,Java提供的GC功能可以自動(dòng)監(jiān)測對(duì)象是否超過作用域從而達(dá)到自動(dòng)回收內(nèi)存的目的,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法炉媒。
簡述synchronized 和java.util.concurrent.locks.Lock的異同踪区?
主要相同點(diǎn):
Lock能完成synchronized所實(shí)現(xiàn)的所有功能
主要不同點(diǎn):
Lock有比synchronized更精確的線程語義和更好的性能。synchronized會(huì)自動(dòng)釋放鎖吊骤,而Lock一定要求程序員手工釋放缎岗,并且必須在finally從句中釋放
Java中的泛型是什么?使用泛型的好處是什么?
這是在各種Java泛型面試中白粉,一開場你就會(huì)被問到的問題中的一個(gè)传泊,主要集中在初級(jí)和中級(jí)面試中鼠渺。那些擁有Java1.4或更早版本的開發(fā)背景的人都知道,在JavaSE中存儲(chǔ)對(duì)象并在使用前進(jìn)行類型轉(zhuǎn)換是多么的不方便眷细。泛型防止了那種情況的發(fā)生拦盹。它提供了編譯期的類型安全,確保你只能把正確類型的對(duì)象放入JavaSE中溪椎,避免了在運(yùn)行時(shí)出現(xiàn)ClassCastException普舆。
JavaSE類框架的基本接口有哪些?
JavaJavaSE類提供了一套設(shè)計(jì)良好的支持對(duì)一組對(duì)象進(jìn)行操作的接口和類校读。
- 1.Collection:代表一組對(duì)象奔害,每一個(gè)對(duì)象都是它的子元素。
- 2.Set:不包含重復(fù)元素的Collection地熄。
- 3.List:有順序的collection华临,并且可以包含重復(fù)元素。
- 4.Map:可以把鍵(key)映射到值(value)的對(duì)象端考,鍵不能重復(fù)雅潭。
問答題 為什么JavaSE類沒有實(shí)現(xiàn)Cloneable和Serializable接口?
克隆(cloning)或者是序列化(serialization)的語義和含義是跟具體的實(shí)現(xiàn)相關(guān)的却特。因此扶供,應(yīng)該由JavaSE類的具體實(shí)現(xiàn)來決定如何被克隆或者是序列化。
Java中的HashMap的工作原理是什么裂明?
Java中的HashMap是以鍵值對(duì)(key-value)的形式存儲(chǔ)元素的椿浓。HashMap需要一個(gè)hash函數(shù),它使用hashCode() 和equals()方法從JavaSE添加和檢索元素闽晦。當(dāng)調(diào)用put()方法的時(shí)候扳碍,HashMap會(huì)計(jì)算key的hash值,然后把鍵值對(duì)存儲(chǔ)在JavaSE 中合適的索引上仙蛉。如果key已經(jīng)存在了笋敞,value會(huì)被更新成新值。HashMap的一些重要的特性是它的容量(capacity)荠瘪,負(fù)載因子(load factor)和擴(kuò)容極限(threshold resizing)夯巷。
hashCode()和equals()方法的重要性體現(xiàn)在什么地方?
Java中的HashMap使用hashCode()和equals()方法來確定鍵值對(duì)的索引哀墓,當(dāng)根據(jù)鍵獲取值的時(shí)候也會(huì)用到這兩個(gè)方法趁餐。如果沒 有正確的實(shí)現(xiàn)這兩個(gè)方法,兩個(gè)不同的鍵可能會(huì)有相同的hash值篮绰,因此后雷,可能會(huì)被JavaSE認(rèn)為是相等的。而且,這兩個(gè)方法也用來發(fā)現(xiàn)重復(fù)元素喷面。所以這兩個(gè)方法 的實(shí)現(xiàn)對(duì)HashMap的精確性和正確性是至關(guān)重要的星瘾。
數(shù)組(Array)和列表(ArrayList)有什么區(qū)別走孽?什么時(shí)候應(yīng)該使用Array而不是ArrayList惧辈?
下面列出了Array和ArrayList的不同點(diǎn):
- 1.Array可以包含基本類型和對(duì)象類型,ArrayList只能包含對(duì)象類型磕瓷。
- 2.Array大小是固定的盒齿,ArrayList的大小是動(dòng)態(tài)變化的。
- 3.ArrayList提供了更多的方法和特性困食,比如:addAll()边翁,removeAll(),iterator()等等硕盹。
- 4.對(duì)于基本類型數(shù)據(jù)符匾,JavaSE使用自動(dòng)裝箱來減少編碼工作量。但是瘩例,當(dāng)處理固定大小的基本數(shù)據(jù)類型的時(shí)候啊胶,這種方式相對(duì)比較慢。
Comparable和Comparator接口是干什么的垛贤?列出它們的區(qū)別焰坪。
Comparable和Comparator接口
Java提供了只包含一個(gè)compareTo()方法的Comparable接口。這個(gè)方法可以個(gè)給兩個(gè)對(duì)象排序聘惦。具體來說某饰,它返回負(fù)數(shù),0善绎,正數(shù)來表明輸入對(duì)象小于黔漂,等于,大于已經(jīng)存在的對(duì)象禀酱。
Java提供了包含compare()和equals()兩個(gè)方法的Comparator接口瘟仿。compare()方法用來給兩個(gè)輸入?yún)?shù)排序,返 回負(fù)數(shù)比勉,0劳较,正數(shù)表明第一個(gè)參數(shù)是小于,等于浩聋,大于第二個(gè)參數(shù)观蜗。equals()方法需要一個(gè)對(duì)象作為參數(shù),它用來決定輸入?yún)?shù)是否和 comparator相等衣洁。只有當(dāng)輸入?yún)?shù)也是一個(gè)comparator并且輸入?yún)?shù)和當(dāng)前comparator的排序結(jié)果是相同的時(shí)候墓捻,這個(gè)方法才返回 true。
HashSet和TreeSet有什么區(qū)別?
HashSet和TreeSet的區(qū)別
- HashSet是由一個(gè)hash表來實(shí)現(xiàn)的砖第,因此撤卢,它的元素是無序的。add()梧兼,remove()放吩,contains()方法的時(shí)間復(fù)雜度是O(1)。
- TreeSet是由一個(gè)樹形的結(jié)構(gòu)來實(shí)現(xiàn)的羽杰,它里面的元素是有序的渡紫。因此,add()考赛,remove()惕澎,contains()方法的時(shí)間復(fù)雜度是O(logn)。
List<? extends T>和List <? super T>之間有什么區(qū)別 ?
這兩個(gè)List的聲明都是限定通配符的例子颜骤,List<? extends T>可以接受任何繼承自T的類型的List唧喉,而List<? super T>可以接受任何T的父類構(gòu)成的List。例如List<? extends Number>可以接受List或List忍抽。
Array中可以用泛型嗎?
Array事實(shí)上并不支持泛型八孝,這也是為什么Joshua Bloch在Effective Java一書中建議使用List來代替Array,因?yàn)長ist可以提供編譯期的類型安全保證梯找,而Array卻不能唆阿。
Java中List<Object>和原始類型List之間的區(qū)別?
原始類型和帶參數(shù)類型之間的主要區(qū)別是,在編譯時(shí)編譯器不會(huì)對(duì)原始類型進(jìn)行類型安全檢查锈锤,卻會(huì)對(duì)帶參數(shù)的類型進(jìn)行檢查驯鳖,通過使用Object作為類型,可以告知編譯器該方法可以接受任何類型的對(duì)象久免,比如String或Integer浅辙。這道題的考察點(diǎn)在于對(duì)泛型中原始類型的正確理解。它們之間的第二點(diǎn)區(qū)別是阎姥,你可以把任何帶參數(shù)的類型傳遞給原始類型List记舆,但卻不能把List傳遞給接受List的方法,因?yàn)闀?huì)產(chǎn)生編譯錯(cuò)誤呼巴。
解釋內(nèi)存中的棧(stack)泽腮、堆(heap)和方法區(qū)(method area)的用法?
棧(stack)、堆(heap)和方法區(qū)(method area)
通常我們定義一個(gè)基本數(shù)據(jù)類型的變量衣赶,一個(gè)對(duì)象的引用诊赊,還有就是函數(shù)調(diào)用的現(xiàn)場保存都使用JVM中的棧空間府瞄;而通過new關(guān)鍵字和構(gòu)造器創(chuàng)建的對(duì)象則放在堆空間碧磅,堆是垃圾收集器管理的主要區(qū)域,由于現(xiàn)在的垃圾收集器都采用分代收集算法,所以堆空間還可以細(xì)分為新生代和老生代鲸郊,再具體一點(diǎn)可以分為Eden丰榴、Survivor(又可分為From Survivor和To Survivor)、Tenured秆撮。
方法區(qū)和堆都是各個(gè)線程共享的內(nèi)存區(qū)域四濒,用于存儲(chǔ)已經(jīng)被JVM加載的類信息、常量像吻、靜態(tài)變量峻黍、JIT編譯器編譯后的代碼等數(shù)據(jù)复隆;程序中的字面量(literal)如直接書寫的100拨匆、"hello"和常量都是放在常量池中,常量池是方法區(qū)的一部分挽拂。棽衙浚空間操作起來最快但是棧很小,通常大量的對(duì)象都是放在堆空間亏栈,棧和堆的大小都可以通過JVM的啟動(dòng)參數(shù)來進(jìn)行調(diào)整台腥,棧空間用光了會(huì)引發(fā)StackOverflowError绒北,而堆和常量池空間不足則會(huì)引發(fā)OutOfMemoryError黎侈。
你了解大O符號(hào)(big-O notation)么?
大O符號(hào)
大O符號(hào)描述了當(dāng)數(shù)據(jù)結(jié)構(gòu)里面的元素增加的時(shí)候闷游,算法的規(guī)木海或者是性能在最壞的場景下有怎樣的表現(xiàn)。
大O符號(hào)也可用來描述其他的行為脐往,比如:內(nèi)存消耗休吠。因?yàn)镴avaSE類實(shí)際上是數(shù)據(jù)結(jié)構(gòu),我們一般使用大O符號(hào)基于時(shí)間业簿,內(nèi)存和性能來選擇最好的實(shí)現(xiàn)瘤礁。大O符號(hào)可以對(duì)大量數(shù)據(jù)的性能給出一個(gè)很好的說明。
什么是線程局部變量梅尤?
線程局部變量是局限于線程內(nèi)部的變量柜思,屬于線程自身所有,不在多個(gè)線程間共享巷燥。Java提供 ThreadLocal 類來支持線程局部變量赡盘,是一種實(shí)現(xiàn)線程安全的方式。但是在管理環(huán)境下(如 web 服務(wù)器)使用線程局部變量的時(shí)候要特別小心矾湃,在這種情況下亡脑,工作線程的生命周期比任何應(yīng)用變量的生命周期都要長。任何線程局部變量一旦在工作完成后沒有釋放,Java 應(yīng)用就存在內(nèi)存泄露的風(fēng)險(xiǎn)霉咨。
Java中能創(chuàng)建volatile數(shù)組嗎蛙紫?
能,Java 中可以創(chuàng)建 volatile 類型數(shù)組途戒,不過只是一個(gè)指向數(shù)組的引用坑傅,而不是整個(gè)數(shù)組。如果改變引用指向的數(shù)組喷斋,將會(huì)受到 volatile 的保護(hù)唁毒,但是如果多個(gè)線程同時(shí)改變數(shù)組的元素,volatile 標(biāo)示符就不能起到之前的保護(hù)作用了星爪。
volatile能使得一個(gè)非原子操作變成原子操作嗎浆西?
一個(gè)典型的例子是在類中有一個(gè) long 類型的成員變量。如果你知道該成員變量會(huì)被多個(gè)線程訪問顽腾,如計(jì)數(shù)器近零、價(jià)格等,你最好是將其設(shè)置為 volatile抄肖。為什么久信?因?yàn)镴ava中讀取long類型變量不是原子的,需要分成兩步漓摩,如果一個(gè)線程正在修改該 long 變量的值裙士,另一個(gè)線程可能只能看到該值的一半(前 32 位)。但是對(duì)一個(gè)volatile型的long或double變量的讀寫是原子管毙。
你對(duì)volatile修飾符的使用有過什么實(shí)踐腿椎?
一種實(shí)踐是用 volatile 修飾 long 和 double 變量,使其能按原子類型來讀寫锅风。double 和 long 都是64位寬酥诽,因此對(duì)這兩種類型的讀是分為兩部分的,第一次讀取第一個(gè) 32 位皱埠,然后再讀剩下的 32 位肮帐,這個(gè)過程不是原子的,但 Java 中 volatile 型的 long 或 double 變量的讀寫是原子的边器。volatile 修復(fù)符的另一個(gè)作用是提供內(nèi)存屏障(memory barrier)训枢,例如在分布式框架中的應(yīng)用。簡單的說忘巧,就是當(dāng)你寫一個(gè) volatile 變量之前恒界,Java 內(nèi)存模型會(huì)插入一個(gè)寫屏障(write barrier),讀一個(gè) volatile 變量之前砚嘴,會(huì)插入一個(gè)讀屏障(read barrier)十酣。意思就是說涩拙,在你寫一個(gè) volatile 域時(shí),能保證任何線程都能看到你寫的值耸采,同時(shí)兴泥,在寫之前,也能保證任何數(shù)值的更新對(duì)所有線程是可見的虾宇,因?yàn)閮?nèi)存屏障會(huì)將其他所有寫的值更新到緩存搓彻。
volatile 類型變量提供什么保證?
volatile變量提供順序和可見性保證嘱朽,例如旭贬,JVM或者JIT為了獲得更好的性能會(huì)對(duì)語句重排序,但是volatile類型變量即使在沒有同步塊的情況下賦值也不會(huì)與其他語句重排序搪泳。volatile提供happens-before的保證稀轨,確保一個(gè)線程的修改能對(duì)其他線程是可見的。某些情況下森书,volatile 還能提供原子性靶端,如讀64位數(shù)據(jù)類型谎势,像 long 和 double 都不是原子的凛膏,但 volatile 類型的 double 和 long 就是原子的。
Java 中 ++ 操作符是線程安全的嗎脏榆?
不是線程安全的操作猖毫。它涉及到多個(gè)指令,如讀取變量值须喂,增加吁断,然后存儲(chǔ)回內(nèi)存,這個(gè)過程可能會(huì)出現(xiàn)多個(gè)線程交差坞生。
Java中的兩種異常類型是什么仔役?他們有什么區(qū)別?
Java中有兩種異常:受檢查的(checked)異常和不受檢查的(unchecked)異常是己。不受檢查的異常不需要在方法或者是構(gòu)造函數(shù)上聲 明又兵,就算方法或者是構(gòu)造函數(shù)的執(zhí)行可能會(huì)拋出這樣的異常,并且不受檢查的異匙浞希可以傳播到方法或者是構(gòu)造函數(shù)的外面沛厨。相反,受檢查的異常必須要用 throws語句在方法或者是構(gòu)造函數(shù)上聲明摔认。
列出一些你常見的運(yùn)行時(shí)異常逆皮?
常見的運(yùn)行時(shí)異常
- ArithmeticException(算術(shù)異常)
- ClassCastException (類型轉(zhuǎn)換異常)
- IllegalArgumentException (非法參數(shù)異常)
- IndexOutOfBoundsException (腳標(biāo)越界異常)
- NullPointerException (空指針異常)
- SecurityException (安全異常)
Java中什么是構(gòu)造函數(shù)?什么是構(gòu)造函數(shù)重載参袱?什么是復(fù)制構(gòu)造函數(shù)电谣?
構(gòu)造函數(shù)
- 當(dāng)新對(duì)象被創(chuàng)建的時(shí)候秽梅,構(gòu)造函數(shù)會(huì)被調(diào)用。每一個(gè)類都有構(gòu)造函數(shù)剿牺。在程序員沒有給類提供構(gòu)造函數(shù)的情況下风纠,Java編譯器會(huì)為這個(gè)類創(chuàng)建一個(gè)默認(rèn)的構(gòu)造函數(shù)。
- Java中構(gòu)造函數(shù)重載和方法重載很相似牢贸≈窆郏可以為一個(gè)類創(chuàng)建多個(gè)構(gòu)造函數(shù)。每一個(gè)構(gòu)造函數(shù)必須有它自己唯一的參數(shù)列表潜索。
- Java不支持像C++中那樣的復(fù)制構(gòu)造函數(shù)臭增,這個(gè)不同點(diǎn)是因?yàn)槿绻悴蛔约簩憳?gòu)造函數(shù)的情況下,Java不會(huì)創(chuàng)建默認(rèn)的復(fù)制構(gòu)造函數(shù)竹习。
short s1 = 1; s1 = s1 + 1;有錯(cuò)嗎?short s1 = 1; s1 += 1;有錯(cuò)嗎
過程如下:
對(duì)于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)換。
數(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)墨礁?
你打車上了高速幢竹,發(fā)現(xiàn)在司機(jī)在兜圈子。于是你要他找個(gè)路口出去恩静,這個(gè)路口肯定有牌子焕毫,不然你和司機(jī)都不知道從哪出。
語言也是一樣的蜕企, 在最外層循環(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í)不知道更好。
當(dāng)一個(gè)對(duì)象被當(dāng)作參數(shù)傳遞到一個(gè)方法后腔召,此方法可改變這個(gè)對(duì)象的屬性杆查,并可返回變化后的結(jié)果,那么這里到底是值傳遞還是引用傳遞臀蛛?
是值傳遞亲桦。Java語言的方法調(diào)用只支持參數(shù)的值傳遞。當(dāng)一個(gè)對(duì)象實(shí)例作為一個(gè)參數(shù)被傳遞到方法中時(shí)浊仆,參數(shù)的值就是對(duì)該對(duì)象的引用客峭。對(duì)象的屬性可以在被調(diào)用過程中被改變,但對(duì)對(duì)象引用的改變是不會(huì)影響到調(diào)用者的抡柿。
Java中的final關(guān)鍵字有哪些用法舔琅?
final的作用:
- 修飾類:表示該類不能被繼承。
- 修飾方法:表示方法不能被重寫洲劣。
- 修飾變量:表示變量只能一次賦值以后值不能被修改(常量)备蚓。
&和&&的區(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)算符(||)的差別也是如此。
抽象的(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è)對(duì)象翻斟,一個(gè)類不管創(chuàng)建多少個(gè)對(duì)象,靜態(tài)變量在內(nèi)存中有且僅有一個(gè)拷貝说铃;實(shí)例變量必須依存于某一實(shí)例访惜,需要先創(chuàng)建對(duì)象然后通過對(duì)象才能訪問到它。靜態(tài)變量可以實(shí)現(xiàn)讓多個(gè)對(duì)象共享內(nèi)存腻扇。
final债热、finally、finalize有什么區(qū)別?
區(qū)別如下:
- final:修飾符(關(guān)鍵字)有三種用法:如果一個(gè)類被聲明為final幼苛,意味著它不能再派生出新的子類窒篱,即不能被繼承。將變量聲明為final舶沿,可以保證它們?cè)谑褂弥胁槐桓淖兡馍蓿宦暶鳛閒inal的變量必須在聲明時(shí)給定初值,而在以后的引用中只能讀取不可修改勾缭。被聲明為final的方法也同樣只能使用提揍,不能在子類中被重寫。
- finally:通常放在try…catch…的后面構(gòu)造總是執(zhí)行代碼塊畸冲,這就意味著程序無論正常執(zhí)行還是發(fā)生異常嫉髓,這里的代碼只要JVM不關(guān)閉都能執(zhí)行,可以將釋放外部資源的代碼寫在finally塊中邑闲。
- finalize:Object類中定義的方法算行,Java中允許使用finalize()方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前做必要的清理工作。這個(gè)方法是由垃圾收集器在銷毀對(duì)象前調(diào)用的苫耸,通過重寫finalize()方法可以整理系統(tǒng)資源或者執(zhí)行其他清理工作州邢。
當(dāng)一個(gè)線程進(jìn)入一個(gè)對(duì)象的synchronized方法A之后,其它線程是否可進(jìn)入此對(duì)象的synchronized方法B鲸阔?
不能偷霉。其它線程只能訪問該對(duì)象的非同步方法迄委,同步方法則不能進(jìn)入。因?yàn)榉庆o態(tài)方法上的synchronized修飾符要求執(zhí)行方法時(shí)要獲得對(duì)象的鎖类少,如果已經(jīng)進(jìn)入A方法說明對(duì)象鎖已經(jīng)被取走叙身,那么試圖進(jìn)入B方法的線程就只能在等鎖池(注意不是等待池哦)中等待對(duì)象的鎖。
char型變量中能不能存儲(chǔ)一個(gè)中文漢字硫狞,為什么信轿?
char類型可以存儲(chǔ)一個(gè)中文漢字,因?yàn)镴ava中使用的編碼是Unicode(不選擇任何特定的編碼残吩,直接使用字符在字符集中的編號(hào)财忽,這是統(tǒng)一的唯一方法),一個(gè)char類型占2個(gè)字節(jié)(16比特)泣侮,所以放一個(gè)中文是沒問題的即彪。
什么是不可變對(duì)象(immutable object)?
不可變對(duì)象指對(duì)象一旦被創(chuàng)建活尊,狀態(tài)就不能再改變隶校。任何修改都會(huì)創(chuàng)建一個(gè)新的對(duì)象,如 String蛹锰、Integer及其它包裝類深胳。
什么是隱式類型轉(zhuǎn)換?什么是顯式類型轉(zhuǎn)換铜犬?
當(dāng)將占位數(shù)少的類型賦值給占位數(shù)多的類型時(shí)舞终,Java自動(dòng)使用隱式類型轉(zhuǎn)換(如int型轉(zhuǎn)為long型)。當(dāng)把在級(jí)別高的變量的值賦給級(jí)別底變量時(shí)癣猾,必須使用顯示類型轉(zhuǎn)換運(yùn)算(如double型轉(zhuǎn)為float型)敛劝。
解釋什么是類方法,什么是實(shí)例方法
static修飾的方法是類方法煎谍,無static修飾的方法是實(shí)例方法攘蔽。
堆內(nèi)存和客棧內(nèi)存的區(qū)別是什么
線程的對(duì)內(nèi)存控件是共享的,棧內(nèi)存控件才是獨(dú)立的(堆共享呐粘,棧獨(dú)立)
構(gòu)造方法能否被重寫?為什么转捕?
不能作岖,因?yàn)闃?gòu)造方法不能被繼承,所以不能重寫五芝。
不能痘儡,因?yàn)闃?gòu)造方法不能被繼承,所以不能重寫枢步。
java關(guān)鍵字一律小寫沉删。所以無所謂區(qū)分大小寫渐尿,大寫的不是關(guān)鍵字。
java關(guān)鍵字一律小寫矾瑰。所以無所謂區(qū)分大小寫砖茸,大寫的不是關(guān)鍵字。
Java使用unicode字符集殴穴,所以常量共有65535個(gè)凉夯。
簡述一個(gè)java程序執(zhí)行的過程?
首先編寫java源文件(擴(kuò)展名為.java的文本文檔)。用javac命令把源文件編譯成字節(jié)碼文件.class文件采幌,再用java命令執(zhí)行字節(jié)碼文件劲够。
靜態(tài)內(nèi)部類、內(nèi)部類休傍、匿名內(nèi)部類征绎,為什么內(nèi)部類會(huì)持有外部類的引用?持有的引用是this磨取?還是其它人柿?
靜態(tài)內(nèi)部類:使用static修飾的內(nèi)部類內(nèi)部類:就是在某個(gè)類的內(nèi)部又定義了一個(gè)類,內(nèi)部類所嵌入的類稱為外部類匿名內(nèi)部類:使用new生成的內(nèi)部類因?yàn)閮?nèi)部類的產(chǎn)生依賴于外部類寝衫,持有的引用是類名.this顷扩。
我們能創(chuàng)建一個(gè)包含可變對(duì)象的不可變對(duì)象嗎?
我們是可以創(chuàng)建一個(gè)包含可變對(duì)象的不可變對(duì)象慰毅,你只需要謹(jǐn)慎一點(diǎn)隘截,不要共享可變對(duì)象的引用就可以了,如果需要變化時(shí)汹胃,就返回原對(duì)象的一個(gè)拷貝婶芭。
Java中try catch finally的執(zhí)行順序
先執(zhí)行try中代碼,運(yùn)行至某一行發(fā)生異常時(shí)try中的代碼將不會(huì)被執(zhí)行着饥,轉(zhuǎn)而執(zhí)行catch中的代碼犀农,最后一定會(huì)執(zhí)行finally中代碼。
Java中應(yīng)該使用什么數(shù)據(jù)類型來代表價(jià)格宰掉?
如果不是特別關(guān)心內(nèi)存和性能的話呵哨,使用BigDecimal,否則使用預(yù)定義精度的double類型轨奄。
我們能將 int 強(qiáng)制轉(zhuǎn)換為 byte 類型的變量嗎孟害?如果該值大于 byte 類型的范圍,將會(huì)出現(xiàn)什么現(xiàn)象挪拟?
面試官問你這個(gè)問題挨务,你就說:我們可以做強(qiáng)制轉(zhuǎn)換,但是Java中int是32位的,而byte是8位的谎柄,所以丁侄,如果強(qiáng)制轉(zhuǎn)化是,int類型的高24位將會(huì)被丟棄朝巫,byte類型的范圍是從 -128 到 128鸿摇。
switch是否能作用在byte上,是否能作用在long上捍歪,是否能作用在String上户辱?
switch支持使用byte類型,不支持long類型糙臼,String支持在java1.7引入
我能在不進(jìn)行強(qiáng)制轉(zhuǎn)換的情況下將一個(gè) double 值賦值給 long 類型的變量嗎庐镐?
面試官問你這個(gè)問題,你就說:沒有強(qiáng)制類型轉(zhuǎn)換的前提下將一個(gè) double 不能賦值給 long 類型的變量变逃,因?yàn)?double 類型的范圍要比 long 類型更大必逆,因此要做強(qiáng)制轉(zhuǎn)換。
int和Integer 哪個(gè)會(huì)占用更多的內(nèi)存揽乱?
經(jīng)驗(yàn)總結(jié):
尾巴帶個(gè)er的名眉,那肯定內(nèi)存用得多,因?yàn)槟氵€得new它凰棉。
Integer對(duì)象會(huì)占用更多的內(nèi)存损拢。Integer是一個(gè)對(duì)象,需要存儲(chǔ)對(duì)象的元數(shù)據(jù)撒犀。但是 int 是一個(gè)原始類型的數(shù)據(jù)福压,所以占用的空間更少。
為什么Java中的String是不可變的(Immutable)或舞?
經(jīng)驗(yàn)總結(jié):
其實(shí)就是設(shè)計(jì)Java內(nèi)庫的那個(gè)大神荆姆,認(rèn)為字符串經(jīng)常被用到,如果在內(nèi)存里new那么多同樣的東西映凳,很占位置胆筒。那干脆就弄成不可變的,這樣大家共享同樣的字符串诈豌,就不會(huì)出問題仆救。
Java中的構(gòu)造器鏈?zhǔn)鞘裁矗?/h2>
經(jīng)驗(yàn)總結(jié):
說實(shí)話,我也是第一次聽到這個(gè)說法矫渔。直到有一個(gè)哥們?nèi)ッ嬖嚮貋砀嬖V我面試官問了他這么一個(gè)問題派桩。我才明白,現(xiàn)在的面試官都喜歡玩這些蚌斩。
后來想了想,不就是我構(gòu)造函數(shù)里調(diào)用了另外一個(gè)構(gòu)造函數(shù)么?
當(dāng)你從一個(gè)構(gòu)造器中調(diào)用另一個(gè)構(gòu)造器送膳,就是Java 中的構(gòu)造器鏈员魏。這種情況只在重載了類的構(gòu)造器的時(shí)候才會(huì)出現(xiàn)。
簡述正則表達(dá)式及其用途叠聋。
經(jīng)驗(yàn)總結(jié):
這種問題一般不會(huì)用嘴巴問你撕阎,最多就是簡答或者填空題里給你來一發(fā),也太簡單了碌补。
在編寫處理字符串的程序時(shí)虏束,經(jīng)常會(huì)有查找符合某些復(fù)雜規(guī)則的字符串的需要。正則表達(dá)式就是用于描述這些規(guī)則的工具厦章。換句話說镇匀,正則表達(dá)式就是記錄文本規(guī)則的代碼。袜啃。
Java中是如何支持正則表達(dá)式操作的汗侵?
面試經(jīng)驗(yàn):
說實(shí)話,正則很有用群发,但平時(shí)也確實(shí)用得不多晰韵。正則里各種火星文符號(hào)也沒那么容易記住,我們只要記得一些簡單API就行了熟妓。 一下幾個(gè)String里常用的方法雪猪,能說幾個(gè)出來就OK。
Java中的String類提供了支持正則表達(dá)式操作的方法起愈,包括:matches()只恨、replaceAll()、replaceFirst()告材、split()坤次。此外,Java中可以用Pattern類表示正則表達(dá)式對(duì)象斥赋,它提供了豐富的JavaSE進(jìn)行各種正則表達(dá)式操作缰猴。
什么情況會(huì)產(chǎn)生死鎖?
產(chǎn)生死鎖的四個(gè)必要條件?
互斥條件:一個(gè)資源每次只能被一個(gè)進(jìn)程使用疤剑。
請(qǐng)求與保持條件:一個(gè)進(jìn)程因請(qǐng)求資源而阻塞時(shí)滑绒,對(duì)已獲得的資源保持不放。
不剝奪條件:進(jìn)程已獲得的資源隘膘,在末使用完之前疑故,不能強(qiáng)行剝奪。
循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系弯菊。