序言:找工作絕逼是一件非常痛苦的事,尤其是年底找工作,當然了,這其中大部分原因肯定是因為LZ只是個沒有經(jīng)驗的,還沒畢業(yè)的大學(xué)生。今天看到一句掉渣天的罵人的話:“你TM就是一個沒有對象的野指針”,哈哈哈!扯淡就到這,下面進入正題(如有錯誤,請及時糾正)。
寫給小白的android基礎(chǔ)面試筆試題(一)
寫給小白的android基礎(chǔ)面試筆試題(二)
寫給小白的android基礎(chǔ)面試筆試題(三)
注:每個問題的最后都會有正確答案(粗體的就是正確答案)
1、請簡述一下你對Handler機制的理解?
答:這道題呢不管是在筆試中也好面試中也好,會被經(jīng)常拿來問,因為這里面涉及到的知識點甚多,這里你就要回答什么是Handler機制,有何作用,然后面試官肯定還會問,Handler的幾個老朋友Message,Looper以及MessageQueue和Handler有什么關(guān)系。所以這里你必須要搞懂這個:
答:首先呢,Handler機制是Android中異步消息處理機制,也就是異步消息處理線程啟動后會進入一個無限的循環(huán)體之中,每循環(huán)一次,從其內(nèi)部的消息隊列中取出一個消息,然后回調(diào)相應(yīng)的消息處理函數(shù),執(zhí)行完成一個消息后則繼續(xù)循環(huán)。若消息隊列為空,消息則會阻塞等待。而他們之間的關(guān)系就是,消息循環(huán)Looper負責創(chuàng)建一個消息隊列MessageQueue,而消息隊列MessageQueue是消息Message的容器,也就是裝消息Message的地方,然后進入一個無限循環(huán)體不斷從該消息隊列MessageQueue中讀取消息,而消息的創(chuàng)建者和處理者就是一個或多個Handler。
2、android項目目錄中res目錄和assets目錄的區(qū)別?
答:這是筆試題中遇到的,不止一道關(guān)于res目錄和assets目錄的,下面我們會好好講解這兩個目錄。
答:首先呢,這兩個目錄的相同點就是目錄下的文件都不會被編譯為二進制文件,這兩個文件夾下的內(nèi)容會保持原樣;不同點是:
(1)、res:該目錄下的文件都會自動在R.java中生成資源id,可以通過getResources的相關(guān)方法結(jié)合其他類進行訪問;而且res目錄下不能隨意創(chuàng)建文件夾。
(2)、assets:該目錄支持創(chuàng)建任意深度的文件夾,并且目錄下的文件不會在R.java中生成資源id,必須使用/assets開始的相對路徑按照文件的方式進行訪問。可以使用AssetManager 結(jié)合其他類進行訪問。
不過這里需要注意一點,assets目錄下不僅僅可以存放音頻、字體等較大的文件,還可以存放大的圖片
3、對Java的設(shè)計模式了解多少?用過哪些設(shè)計模式(我回答了下面幾個,然后他又發(fā)問了)?說說你對單例模式的了解?
答:OMG!我的第一反應(yīng)就是這個問題問的就有點深了,后來想想其實也還好,只是問你用過的一些,然后我就講了幾個我用到過的,單例模式、適配器模式、建造者模式、觀察者模式,好像沒了,像其他的一些工廠模式、策略模式、訪問者模式什么的都只是聽過,可能用到過,但是自己不知道而已>_<
答:首先解釋一下單例模式:為了確保某個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。單例模式的特點:
(1)、單例模式只能有一個實例。
(2)、單例類必須自己創(chuàng)建自己的唯一實例。
(3)、單例類必須給所有其他對象提供這一實例。
單例模式通常在一些或多或少具有資源管理器的功能的地方使用,比如說線程池、緩存、對話框等等。我覺得對于像我這樣一個初級的猿猿來說懂這些應(yīng)該就夠了,當然了,你還得知道單例模式的幾種寫法,看到這里的童鞋,請移步JAVA設(shè)計模式之單例模式,里面有比較詳細的講解
4、你用過Gradle嗎?(呃!我用的是studio開發(fā),所以gradle還是經(jīng)常用的)請說說你知道的gradle的一些用法(配置)?
答:這道題,說真的,我剛開始有點懵逼,我之前看到過講的很詳細的關(guān)于Gradle的博文,但是可悲的是我沒有仔細去研究;相信大家都知道Maven吧!Gradle的功能比Maven還要強大。然后你可以先介紹一下Gradle是個啥,然后再講講你知道的一些Gradle配置,然后基本就差不多了。
Gradle是一個基于Apache Ant和Apache Maven概念的項目自動化建構(gòu)工具。它使用一種基于Groovy的特定領(lǐng)域語言(DSL)來聲明項目設(shè)置,拋棄了基于XML的各種繁瑣配置。在Android Studio中,我們可以使用Gradle來完成APK的編譯及打包工作。使用Gradle的原因:
(1)、使用領(lǐng)域?qū)S谜Z言(Domain Specific Language)來描述和處理構(gòu)建邏輯。
(2)、基于Groovy。DSL可以混合各種聲明元素,用代碼操控這些DSL元素達到邏輯自定義。
(3)、支持已有的Maven或者Ivy倉庫基礎(chǔ)建設(shè)。
(4)、非常靈活,允許使用best practices,并不強制讓你遵照它的原則來。
(5)、其它插件時可以暴露自己的DSL和API來讓Gradle構(gòu)建文件使用。
(6)、允許IDE集成,是很好的API工具。
在Android Studio中,你可以在Gradle中配置以下內(nèi)容:
(1)、配置插件及插件的屬性
(2)、配置遠程倉庫,像jcenter和maven
(3)、配置所依賴的第三方庫,jar包等
(4)、配置多渠道打包的信息
(5)、配置應(yīng)用的簽名信息,編譯版本信息等等
上面的這些都是比較基礎(chǔ)的一些,想了解更詳細的請移步Gradle從入門到了解
5、Activity的四種狀態(tài)是什么,分別對應(yīng)的Activity的生命周期是什么?
答:這是一道筆試大題,這也是一道比較基礎(chǔ)而且又有考點的題目,有些時候你的知道在哪個狀態(tài)該干些什么事,在生命周期切換的時候可以做哪些事。我當時寫的比較糙,沒怎么寫全,可能自己也有點不記得了,之前看郭神的第一行代碼中寫的比較詳細。
Activity的四種狀態(tài)分別是:
(1)、運行狀態(tài)(Running):當一個Activity在棧頂,它是可視的、有焦點、可接受用戶輸入的。Android試圖盡最大可能保持它活動狀態(tài),殺死其它Activity來確保當前活動Activity有足夠的資源可使用。當另外一個Activity被激活,這個將會被暫停。
(2)、暫停狀態(tài)(Paused):在很多情況下,你的Activity可視但是它沒有焦點,換句話說它被暫停了。有可能原因是一個透明或者非全屏的Activity被激活。當被暫停,一個Activity仍會當成活動狀態(tài),只不過是不可以接受用戶輸入。在極特殊的情況下,Android將會殺死一個暫停的Activity來為活動的Activity提供充足的資源。當一個Activity變?yōu)橥耆[藏,它將會變成停止。
(3)、停止狀態(tài)(Stopped):當一個Activity不是可視的,它“停止”了。這個Activity將仍然在內(nèi)存中保存它所有的狀態(tài)和會員信息。盡管如此,當其它地方需要內(nèi)存時,它將是最有可能被釋放資源的。當一個Activity停止后,一個很重要的步驟是要保存數(shù)據(jù)和當前UI狀態(tài)。一旦一個Activity退出或關(guān)閉了,它將變?yōu)殇N毀狀態(tài)。
(4)、銷毀狀態(tài)(Destroyed):在一個Activity被殺死后和被裝載前,它是銷毀狀態(tài)的。被銷毀Acitivity被移除Activity棧,并且需要在顯示和可用之前重新啟動它。
這四種狀態(tài)還是比較容易理解的,下面我們來看一下和生命周期串聯(lián)起來:
(1)、運行狀態(tài):進入Activity,onCreate—>onStart—>onResume,這時候Activity就處于運行狀態(tài)了。
(2)、暫停狀態(tài):在當前Activity中打開一個半透明的Activity然后再返回來,onPause—>onRestart—>onStart—>onResume,不會運行onStop,這樣Activity就經(jīng)歷了暫停狀態(tài),請注意暫停狀態(tài)和停止狀態(tài)的區(qū)別。
(3)、停止狀態(tài):當前Activity跳轉(zhuǎn)到另外一個Activity然后再返回來,onPause—>onStop—>onRestart—>onStart—>onResume,這樣Activity就經(jīng)歷了暫停狀態(tài)、停止狀態(tài),然后又回到了運行狀態(tài)。
(4)、銷毀狀態(tài):當前Activity按返回鍵,onPause—>onStop—>onDestroy,這時候Activity就被銷毀了,等到下一次被運行。
6、請說說你是怎么優(yōu)化ListView的?
答:這道題說簡單也不簡單,說難應(yīng)該也不算難,如果你搞懂這里面的原理就一點不難,就我個人而言,沒做過的就是分頁加載的邏輯。
優(yōu)化一:在Adapter中的getView方法中使用ConvertView,即ConvertView的復(fù)用,不需要每次都inflate一個View出來,這樣既浪費時間,又浪費內(nèi)存。
優(yōu)化二:使用ViewHolder,不要在getView方法中寫findViewById方法,因為getView方法會執(zhí)行很多遍,這樣也可以節(jié)省時間,節(jié)約內(nèi)存。
優(yōu)化三:使用分頁加載,講真實際開發(fā)中,ListView的數(shù)據(jù)肯定不止幾百條,成千上萬條數(shù)據(jù)你不可能一次性加載出來,所以這里需要用到分頁加載,一次加載幾條或者十幾條,但是如果數(shù)據(jù)量很大的話,像qq,微信這種,如果順利加載到最后面的話,那么你的list中也會有幾萬甚至幾十萬的數(shù)據(jù),這樣可能也會導(dǎo)致OOM,所以你的數(shù)據(jù)集List中也不能有那么多數(shù)據(jù),所以每加載一頁的時候你可以覆蓋前一頁的數(shù)據(jù)。
優(yōu)化四:如果數(shù)據(jù)當中有圖片的話,使用第三方庫來加載(也就是緩存),如果你的能力強大到能自己維護的話,那也不是不可以。
優(yōu)化五:當你手指在滑動列表的時候,盡可能的不加載圖片,這樣的話滑動就會更加流暢。
差不多回答個這么些也就可以了,如果你還有更厲害的,請私戳回復(fù)我一下,咱們共同進步
7、說說你對Java的線程機制的理解?
答:首先呢這道題是在電話面試的時候面試官問的,線程機制如果要講的話會很深,可是LZ回答的時候只是講了一下線程的概念,然后按照自己平常的使用方法講了一下,如果你知道的深的話你可以拿出來裝裝逼了。
首先線程是程序運行的最小單元,有時候被稱為輕量級進程。線程的創(chuàng)建方法有兩種,第一,繼承Thread類,然后實現(xiàn)run方法即可;第二,使用內(nèi)部類實現(xiàn)Runnable接口亦可。
第一種:
public class A extends Thread {
@Override
public void run() {
super.run();
}
}
使用:
new A().start();
第二種:
public class B implements Runnable {
@Override
public void run() {
}
}
使用:
B b=bew B();
new Thread(b).start();
然后可以再說說線程的生命周期,因為這也是一個比較重要的知識點:
(1)、新建狀態(tài):用new關(guān)鍵字和Thread類或其子類建立一個線程對象后,該線程對象就處于新生狀態(tài)
注意:不能對已經(jīng)啟動的線程再次調(diào)用start()方法,否則會出現(xiàn)Java.lang.IllegalThreadStateException異常。
(2)、就緒狀態(tài):處于就緒狀態(tài)的線程已經(jīng)具備了運行條件,但還沒有分配到CPU,處于線程就緒隊列,等待系統(tǒng)為其分配CPU
(3)、運行狀態(tài):處于運行狀態(tài)的線程最為復(fù)雜,它可以變?yōu)樽枞麪顟B(tài)、就緒狀態(tài)和死亡狀態(tài)。
(4)、阻塞狀態(tài):處于運行狀態(tài)的線程在某些情況下,如執(zhí)行了sleep(睡眠)方法,或等待I/O設(shè)備等資源,將讓出CPU并暫時停止自己的運行,進入阻塞狀態(tài)。
(5)、死亡狀態(tài):當線程的run()方法執(zhí)行完,或者被強制性地終止,就認為它死去
注意:線程一旦死亡,就不能復(fù)生。 如果在一個死去的線程上調(diào)用start()方法,會拋出java.lang.IllegalThreadStateException異常。
在Android中,用到線程的地方一般是網(wǎng)絡(luò)請求,大文件的加載等耗時的操作,用到線程的地方大多可能會用到handler,這個上面有講到。
8、說說你對Java的GC機制的理解?GC機制與純計數(shù)方式的自動內(nèi)存管理相比有什么優(yōu)勢?
答:這道題也算是比較經(jīng)典的了,我知道的也比較淺顯,但是GC機制也很重要,所以,正在看這個的你們一定要重視,可以去找找Java中關(guān)于JVM的書籍或者博客去看一看Java中JVM的原理,因為這玩意兒真的很重要。
GC機制算得上是Java語言中一個比較優(yōu)秀的機制了,它能自動管理內(nèi)存的回收,相對于C/C++來說,程序員不必手動調(diào)用方法來釋放內(nèi)存。首先你得了解JVM內(nèi)存的組成結(jié)構(gòu),JVM是由堆、棧、本地方法棧、方法區(qū)等部分組成,至于這些玩意是什么,詳細可以參考深入了解Java GC的工作原理;當程序員使用new關(guān)鍵字創(chuàng)建對象時,GC就開始監(jiān)控這個對象的地址,大小以及使用情況。一般來說,GC是采用有向圖的方式來記錄和管理堆中所有的對象。GC與純計數(shù)方式的自動內(nèi)存管理相比:
(1)、最基本的純引用計數(shù)方式的自動內(nèi)存管理可以做到實時釋放死對象,但卻無法處理存在循環(huán)引用的對象圖的釋放。
(2)、最基本的純引用計數(shù)方式對引用計數(shù)器的操作非常頻繁,這里有額外開銷,至于是否嚴重到成問題就看具體應(yīng)用的可忍受程度。
(3)、如果選用GC來實現(xiàn)自動內(nèi)存管理,它是不顯式維護對象的引用計數(shù)的,也就沒有“引用計數(shù)到0”的概念。所以基于GC的JVM或其它語言的運行時環(huán)境自然不會“引用計數(shù)到0就釋放對象”。
(4)、引用計數(shù)方式其實也有經(jīng)典的卡頓情況。例子之一就是一個對象個數(shù)很多、引用鏈很長的對象圖假如只是被一個引用而留活,那么那個引用一死就會引發(fā)大量對象扎堆釋放(但卻不是“批量釋放”,開銷不同),這一樣會引起卡頓。
另外為了保證GC能夠在不同平臺實現(xiàn)的問題,Java規(guī)范對GC的很多行為都沒有進行嚴格的規(guī)定。例如,對于采用什么類型的回收算法、什么時候進行回收等重要問題都沒有明確的規(guī)定。因此,不同的JVM的實現(xiàn)者往往有不同的實現(xiàn)算法。這也給Java程序員的開發(fā)帶來行多不確定性。
9、說說你對Java中幾種引用的理解?
答:這道題對我來說并不陌生,因為每次看面試題的時候都會經(jīng)??吹?,但是我又真的沒有使用過這些引用,所以我就回答了這幾個引用的概念,面試官后面也問了在什么情況下會使用這些。
首先你得了解這四種引用的概念:
(1)、強引用:如果一個對象具有強引用,它就不會被垃圾回收器回收。即使當前內(nèi)存空間不足,JVM也不會回收它,而是拋出 OutOfMemoryError 錯誤,使程序異常終止。如果想中斷強引用和某個對象之間的關(guān)聯(lián),可以顯式地將引用賦值為null,這樣一來的話,JVM在合適的時間就會回收該對象
(2)、軟引用:在使用軟引用時,如果內(nèi)存的空間足夠,軟引用就能繼續(xù)被使用,而不會被垃圾回收器回收,只有在內(nèi)存不足時,軟引用才會被垃圾回收器回收。
(3)、弱引用:具有弱引用的對象擁有的生命周期更短暫。因為當 JVM 進行垃圾回收,一旦發(fā)現(xiàn)弱引用對象,無論當前內(nèi)存空間是否充足,都會將弱引用回收。不過由于垃圾回收器是一個優(yōu)先級較低的線程,所以并不一定能迅速發(fā)現(xiàn)弱引用對象
(4)、虛引用:顧名思義,就是形同虛設(shè),如果一個對象僅持有虛引用,那么它相當于沒有引用,在任何時候都可能被垃圾回收器回收。
講到這里,LZ又要建議你去看看JVM了,這是一個比較深的知識點。至于在Android項目中在哪里能使用,我只知道內(nèi)存優(yōu)化的使用,比如在你初始化Handler的時候,周圍的顏色會變黃,這個是編譯器提示的,有可能會發(fā)生內(nèi)存泄漏這個問題的,所以你可以給Handler加上軟引用來避免這個問題。其他的也一樣,如果你不想某個東西造成內(nèi)存泄漏,你就可以給它加上軟引用,讓GC來消滅它
10、int和Integer的區(qū)別,String和StringBuilder、StringBuffer的區(qū)別?
答:這道題,首先呢你得知道Java的8種基本的數(shù)據(jù)類型,byte,short,int,long,double,float,char,boolean,他們都有與之對應(yīng)的對象。至于后面那個問題,LZ建議你去看看源碼,這樣的話你就能比較深刻的理解。
首先呢int和Integer前者是基本數(shù)據(jù)類型,后者是一個對象,這沒什么好說的,后面的String和另外兩者的區(qū)別是,String是字符串常量,另外兩個是字符串變量,再說白一點,String是不會變的,而后面的是可變的,這里可能就有人要問了,我在使用字符串想加的時候,String不是也變了嗎?NoNoNo,這里說的不可變是你給他賦初始值之后String就不會變了,你之后用加法的過程中它又創(chuàng)建了一個新的String對象來操作你的加法,原本的初始的String的值仍然沒有改變;然后我們說說后面兩者的區(qū)別,StringBuilder是線程不安全的,因此它操作字符串會比較快,而StringBuffer是線程安全的,所以它操作字符串會比較慢,關(guān)于線程安全這方面,你可以去看看這兩個的源碼。另外你還得知道怎樣合理的使用這三者:
(1)、String:操作少量數(shù)據(jù)的時候使用。
(2)、StringBuilder:單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù)。
(3)、StringBuffer:多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù)。
在此感謝上面引用到的博客的博主?。。?!
今天LZ終于結(jié)束了這20多天尋找工作的旅途,希望我的博客能夠幫到還在找工作的小白,LZ給你們的建議仍然是不要放棄,真的喜歡Android,就做下去吧!