java相關(guān):面試中關(guān)于Java你所需知道的的一切
一:架構(gòu)方面
1、模塊化組件化開發(fā)架構(gòu)
一開始使用比較簡單的架構(gòu) ,界面->邏輯層->工具包層,后面改為分業(yè)務(wù)模塊->工具包,但是業(yè)務(wù)模塊之間存在大量耦合?,F(xiàn)在將業(yè)務(wù)模塊再具體劃分,比如購物流程模塊,地址選擇管理模塊,消息模塊。自己寫的router,沒有用注解,沒有依賴注入,寫了大量的映射和接口注冊。借鑒阿里的Arouter[Alibaba-ARouter] 新版本解讀與控制反轉(zhuǎn)在移動端的應(yīng)用
Arouter:自定義注解
采用arr方式解決重復(fù)依賴
采用新的網(wǎng)絡(luò)請求框架Retrofit+OkHttp,新的圖片及下載框架,okhttp,規(guī)范了接口定義以及數(shù)據(jù)加密等。
當(dāng)然,我們還做了很多的新的嘗試,RecycleView替換了ListView,狀態(tài)欄Immersive Mode設(shè)計,組件化開發(fā)的嘗試,App功能動態(tài)化配置,通用自定義控件設(shè)計以及國際化設(shè)配等。
ARouter的優(yōu)勢:
編譯器處理注解產(chǎn)生映射文件,運行期加載映射文件實現(xiàn)路由
Bootstrapping、Extensibility以及Simple & Enough
編譯期間:頁面自動注冊—注解&注解處理器
運行期間:動態(tài)加載—–分組管理,按需加載
全局?jǐn)r截器
依賴注入
運行期動態(tài)修改路由
降級問題
2、hybrid架構(gòu)
① NativeUI組件,header組件、消息類組件
② 通訊錄、系統(tǒng)、設(shè)備信息讀取接口
③ H5與Native的互相跳轉(zhuǎn),比如H5如何跳到一個Native頁面,H5如何新開Webview做動畫跳到另一個H5頁面
4、數(shù)據(jù)請求,數(shù)據(jù)操作的接口,工具包之類
android中通信方式:
1、傳統(tǒng)的JavascriptInterface,setJavaScriptEnabled呀小心xss攻擊,4.2已修復(fù)
2、JSbridge,定義一套協(xié)議
3、代碼重構(gòu)的經(jīng)驗
首先講述自己的工程架構(gòu)演變,由普通依賴到模塊化組件化,路由結(jié)構(gòu),通信原理,怎樣解耦。然后問面試官對中小型公司自己這一套改進有沒有什么建議,引用RXjava這類開源框架。提到自己對知識的渴望,然而在小公司人員不足和業(yè)務(wù)量不龐大的情況體驗不到它的好處,特別想進大的平臺加深自己對整個架構(gòu)的優(yōu)點的深入理解。
4、AOP OOP
面向切面(從左到右的關(guān)系,將那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝到一個可重用模塊,并將其名為“Aspect”)。Android中應(yīng)用:網(wǎng)絡(luò)請求,圖片操作,數(shù)據(jù)解析,文件操作,Log,格式轉(zhuǎn)換等共用型Util包。
面向?qū)ο螅鹤⒅厣舷聦?,封裝、繼承和多態(tài)性等概念來建立一種對象層次結(jié)構(gòu),允許你定義從上到下的關(guān)系,但并不適合定義從左到右的關(guān)系
二:性能優(yōu)化和內(nèi)存優(yōu)化具體經(jīng)驗
Runtime.getRuntime().maxMemory()最大可分配內(nèi)存
Runtime.getRuntime().freeMemory()當(dāng)前空閑內(nèi)存
Runtime.getRuntime().totalMemory()當(dāng)前占用內(nèi)存
內(nèi)存檢測工具MemoMonitor,android device monitor
優(yōu)化:
數(shù)據(jù)結(jié)構(gòu)的優(yōu)化(1、StringBuilder拼接;2、SparseArray(2個數(shù)組,int型的Key數(shù)組,value數(shù)組)、ArrayMap(hash值的Key數(shù)組,keyvalue成對的數(shù)組)(添加、刪除、查找數(shù)據(jù)的時候都是先使用二分查找法得到相應(yīng)的index)代替HashMap,HashMap初始就會創(chuàng)建容量為16的數(shù)組,而且每次都是以2倍的容量遞增,SparseArray、ArrayMap;3、內(nèi)存抖動;4、使用parcelable代替serializebal,serializebal會產(chǎn)生大量臨時變量引起GC)
對象復(fù)用:列表布局里單Item的復(fù)用,避免在ondraw里進行對象的創(chuàng)建
避免內(nèi)存泄露:內(nèi)存泄漏會導(dǎo)致heap可用內(nèi)存越來越少,這時當(dāng)有一個稍大的內(nèi)存占用,很可能會造成OOM,還有一點它會讓GC頻繁的觸發(fā)造成內(nèi)存抖動。造成內(nèi)存泄漏的一些點:單例使用了context(使用applicationcontext),匿名內(nèi)部類,handler,static變量,資源未關(guān)閉(io流,cursor使用了一定要及時關(guān)閉),asyntask,耗時操作可以考慮使用service
OOM優(yōu)化:大部分是圖片造成的。使用軟引用弱引用;臨死bitmap的及時回收;某些大內(nèi)存分配時可以使用try/catch,即使失敗了也不會崩潰;加載bitmap時注意(縮放比例、解碼格式ARGB_4444、局部加載),LUR cache
三:用到的開源框架原理
okhttp原理:
首先使用建造者模式構(gòu)建request,然后經(jīng)過一系列攔截器(包括跟服務(wù)器橋接的響應(yīng)BridgeInterapter,CacheInterapter,ConnectInterapter,Callserver),攔截器連成了一條鏈InterappetChain.底層用了okio連接,socket。異步請求做了一個線程池的封裝。
多路復(fù)用機制(nextconnection從connection池里獲取到的話,就復(fù)用,獲取不到才create),重連機制(判斷是否能onresponce,獲取不到則recovery,循環(huán))
支持HTTP2/SPDY黑科技
socket自動選擇最好路線,并支持自動重連
擁有自動維護的socket連接池,減少握手次數(shù)
擁有隊列線程池,輕松寫并發(fā)
擁有Interceptors輕松處理請求與響應(yīng)(比如透明GZIP壓縮,LOGGING)
實現(xiàn)基于Headers的緩存策略
volley原理,
glide原理
glide .with(context):所有request請求是通過requestmanagerrechiver這個類把requestmanager綁定到activity或fragment類。創(chuàng)建了一個fragment把requestmanager傳給fragmengt,與activity生命周期綁定
.load(url) : 創(chuàng)建DrawableTypeRequest,添加一系列條件初始化
.into里面將imageview與lifecycle生命周期關(guān)聯(lián)了起來,里面的核心是一個引擎類Engine,里面有個Load,先從緩存中讀取,Engine中包含LruCache緩存及一個當(dāng)前正在使用的active資源Cache(弱引用),Cache優(yōu)先級LruCache>activeCache,從LruCache取出使用了則會放到activeCache,緩存沒有則通過線程池去獲取圖片,Engine在初始化時要傳入兩個ExecutorService,即會有兩個線程池,一個用來從DiskCache獲取resource,另一個用來從Source中獲?。ㄍǔJ窍螺d)。先進入DiskCacheService中執(zhí)行獲取,如果沒找到則進入SourceState,進到SourceService中執(zhí)行下載。
Glide的Target:
負(fù)責(zé)圖片加載的回調(diào)中
4.4以前是Bitmap復(fù)用必須長寬相等才可以復(fù)用
4.4及以后是Size>=所需就可以復(fù)用,只不過需要調(diào)用reconfigure來調(diào)整尺寸
Glide用AttributeStategy和SizeStrategy來實現(xiàn)兩種策略
圖片池在收到傳來的Bitmap之后,通過長寬或者Size來從KeyPool中獲取Key(對象復(fù)用到了極致,連Key都用到了Pool),然后再每個Key對應(yīng)一個雙向鏈表結(jié)構(gòu)來存儲。每個Key下可能有很多個待用Bitmap
取出后要減少圖片池中記錄的當(dāng)前Size等,并對Bitmap進行eraseColor(Color.TRANSPAENT)操作確保可用
butterknife原理
四:Framework層常用模塊原理
AMS和WMS原理
audioflinger原理,
整個音頻系統(tǒng)的核心與難點,啟到承上(為上層提供訪問接口)啟下(通過HAL來管理音頻設(shè)備)的作用。
audiotrack原理,
播放聲音,2種模式,AudioTrack中有MODE_STATIC和MODE_STREAM兩種分類。STREAM的意思是由用戶在應(yīng)用程序通過write方式把數(shù)據(jù)一次一次得寫到audiotrack中。這個和我們在socket中發(fā)送數(shù)據(jù)一樣,應(yīng)用層從某個地方獲取數(shù)據(jù),例如通過編解碼得到PCM數(shù)據(jù),然后write到audiotrack。
這種方式的壞處就是總是在JAVA層和Native層交互,效率損失較大。
而STATIC的意思是一開始創(chuàng)建的時候,就把音頻數(shù)據(jù)放到一個固定的buffer,然后直接傳給audiotrack,后續(xù)就不用一次次得write了。AudioTrack會自己播放這個buffer中的數(shù)據(jù)。
這種方法對于鈴聲等內(nèi)存占用較小,延時要求較高的聲音來說很適用。
vold框架原理,
1,有一個netlinkmanager接收來自Linux內(nèi)核的uevent消息,例如sd卡的插拔會引起kernel向NM發(fā)送uevent消息,
2,netlinkmanager將這些消息轉(zhuǎn)發(fā)給volumeManager,volumeManager做一些操作后將消息通過CommandListener發(fā)送給MountService.MountService收到消息后做進一步處理。比如volumeManager----disk insert-----MountService----Mount----Vold,表示掛載這個SD卡
4,CommandListener內(nèi)部封裝了一個socket用于跨進程通信,在vold進程中屬于服務(wù)端,接收來自mountservice的控制命令,同時volumeManager和netlinkmanager又通過它發(fā)送消息給MountService
dhcp協(xié)議
binder原理:
傳統(tǒng)·IPC·:需要做兩次拷貝:用戶空間->內(nèi)核空間->用戶空間
binder:由Binder驅(qū)動負(fù)責(zé)管理數(shù)據(jù)接收緩存,驅(qū)動會根據(jù)發(fā)送數(shù)據(jù)包的大小,使用最佳匹配算法從緩存池中找到一塊大小合適的空間,將數(shù)據(jù)從發(fā)送緩存區(qū)復(fù)制過來,mmap()分配的內(nèi)存是映射在接收方用戶空間里的.為了實現(xiàn)用戶空間到用戶空間的拷貝,mmap()分配的內(nèi)存除了映射進了接收方進程里,還映射進了內(nèi)核空間。所以調(diào)用copy_from_user()將數(shù)據(jù)拷貝進內(nèi)核空間也相當(dāng)于拷貝進了接收方的用戶空間,這就是Binder只需一次拷貝的‘秘密’。
五:android重要知識點
Android開發(fā)--如何減小Apk文件的大小
靜態(tài)編譯和動態(tài)編譯
靜態(tài) include $(BUILD_STATIC_JAVA_LIBRARY)
動態(tài) include $(BUILD_JAVA_LIBRARY)
a、可以在apk的Android.mk中去添加動態(tài)jar包的依賴,使用的時候jar包的類可以直接調(diào)用
b、apk編譯的時候如果不在android.mk中做動態(tài)jar包的依賴的話,可以在使用的時候去動態(tài)尋找system/framework/SkyFramework的jar包,去load此jar包,在去找jar包中的 ? class;這種方法?apk中可以直接調(diào)用接口中自己定義的方法,編譯時不需要去做android.mk的依賴。 實現(xiàn)的地方直接繼承接口即可,打包到動態(tài)jar包中。
這樣可以實現(xiàn)分離,接口的定義和實現(xiàn)做到分離,在開發(fā)階段非常有用,不同部門直接可以并行進行。
網(wǎng)絡(luò)編程,服務(wù)器端編程
安卓中Fragment應(yīng)用,相比Activity的好處
Fragment可以使你能夠?qū)ctivity分離成多個可重用的組件,每個都有它自己的生命周期和UI。
Fragment可以輕松得創(chuàng)建動態(tài)靈活的UI設(shè)計,可以適應(yīng)于不同的屏幕尺寸。從手機到平板電腦。
Fragment是一個獨立的模塊,緊緊地與activity綁定在一起??梢赃\行中動態(tài)地移除、加入、交換等。
Fragment提供一個新的方式讓你在不同的安卓設(shè)備上統(tǒng)一你的UI。
Fragment 解決Activity間的切換不流暢,輕量切換。
Fragment 替代TabActivity做導(dǎo)航,性能更好。
Fragment 在4.2.版本中新增嵌套fragment使用方法,能夠生成更好的界面效果。
Fragment做局部內(nèi)容更新更方便,原來為了到達這一點要把多個布局放到一個activity里面,現(xiàn)在可以用多Fragment來代替,只有在需要的時候才加載Fragment,提高性能。
可以從startActivityForResult中接收到返回結(jié)果,但是View不能。
recyclerview的復(fù)用原理
熱修復(fù)原理
android7.0原理--簽名機制:
android 7.0中引入了APK Signature Scheme V2(Full APK Signature),而V1(jar Signature) 來自JDK;
V1:僅驗證未解壓的文件內(nèi)容,這樣APK 簽署后可進行許多修改 ,可以移動甚至重新壓縮文件;
V2:驗證壓縮文件的所有字節(jié),而不是單個 ZIP 條目,因此,在簽名后無法再更改(包括 zipalign)。正因如此,現(xiàn)在在編譯過程中,我們將壓縮、調(diào)整和簽署合并成一步完成。好處顯而易見,更安全而且新的簽名可縮短在設(shè)備上進行驗證的時間(不需要費時地解壓縮然后驗證),從而加快應(yīng)用安裝速度。如有任何自定義任務(wù)篡改 APK 文件或?qū)ζ溥M行后處理(無論以任何方式),那么V2 簽名會有作廢的風(fēng)險,從而導(dǎo)致您的 APK 與 Android 7.0 及更高版本不兼容。
六:android重要知識點
java類加載機制
類加載的過程包括了加載(查找并加載類的二進制數(shù)據(jù))、驗證(確保被加載的類的正確性:確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求,并且不會危害虛擬機自身的安全)、準(zhǔn)備(為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值,public static int value = 3,這是設(shè)為0)、解析(把類中的符號引用轉(zhuǎn)換為直接引用)、初始化(類的靜態(tài)變量賦予正確的初始值,JVM負(fù)責(zé)對類進行初始化,主要對類變量進行初始化)五個階段。
解析階段則不一定,它在某些情況下可以在初始化階段之后開始,這是為了支持Java語言的運行時綁定(也成為動態(tài)綁定或晚期綁定)
類加載器:雙親委派模型,如果存在父類加載器,就委派給父類加載器加載,如果不存在父類加載器,就檢查是否是由啟動類加載器加載的類,通過調(diào)用本地方法,如果父類加載器和啟動類加載器都不能完成加載任務(wù),才調(diào)用自身的加載功能。
意義:系統(tǒng)類防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼,-保證Java程序安全穩(wěn)定運行
java編譯過程
分析和輸入到符號表
注解處理
語義分析和生成class字節(jié)碼文件
GC
final用法,反射原理
反射:先講反射機制,反射就是程序運行期間JVM會對任意一個類洞悉它的屬性和方法,對任意一個對象都能夠訪問它的屬性和方法。依靠此機制,可以動態(tài)的創(chuàng)建一個類的對象和調(diào)用對象的方法。
其次就是反射相關(guān)的API,只講一些常用的,比如獲取一個Class對象。Class.forName(完整類名)。通過Class對象獲取類的構(gòu)造方法,class.getConstructor。根據(jù)class對象獲取類的方法,getMethod和getMethods。使用class對象創(chuàng)建一個對象,class.newInstance等。
最后可以說一下反射的優(yōu)點和缺點,優(yōu)點就是增加靈活性,可以在運行時動態(tài)獲取對象實例。缺點是反射的效率很低,而且會破壞封裝,通過反射可以訪問類的私有方法,不安全。
注解原理
io,nio區(qū)別和原理,NIO中select的實現(xiàn)機制
Java IO是面向流的,這意味著我們需要每次從流中讀取一個或多個字節(jié),直到讀取完所有字節(jié);NIO是面向緩沖的,也就是說會把數(shù)據(jù)讀取到一個緩沖區(qū)中,然后對緩沖區(qū)中的數(shù)據(jù)進行相應(yīng)處理。
Java IO是阻塞IO,而NIO是非阻塞IO。
Java NIO中存在一個稱為選擇器(selector)的東西,它允許你把多個通道(channel)注冊到一個選擇器上,然后使用一個線程來監(jiān)視這些通道:若這些通道里有某個準(zhǔn)備好可以開始進行讀或?qū)懖僮髁耍瑒t開始對相應(yīng)的通道進行讀寫。而在等待某通道變?yōu)榭勺x/寫期間,請求對通道進行讀寫操作的線程可以去干別的事情。
多線程同步的幾個方式及區(qū)別
1、synchronized (托管給JVM執(zhí)行的),2、重入鎖(retrandlock,讀寫ReentrantReadWriteLock)3、volatile關(guān)鍵字,阻塞隊列(linkedblockingqueen),是java代碼自己實現(xiàn)的,4、局部變量(ThreadLocal,提到Looper.prepare)5、使用同步容器(vector,hashtable,ConcurrentHashMap),6、CountDownLatch
樂觀鎖和悲觀鎖的區(qū)別
悲觀鎖,就是很悲觀,每次去拿數(shù)據(jù)的時候都認(rèn)為別人會修改,所以每次在拿數(shù)據(jù)的時候都會上鎖,這樣別人想拿這個數(shù)據(jù)就會block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
樂觀鎖,就是很樂觀,每次去拿數(shù)據(jù)的時候都認(rèn)為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù),可以使用版本號等機制。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫如果提供類似于write_condition機制的其實都是提供的樂觀鎖。
synchronized是基于悲觀鎖,比較適用于大量線程頻繁請求,lock是樂觀鎖,適用于不是很頻繁的
ReentrantLock非中斷鎖(一直等待)和中斷鎖(lock.lockInterruptibly()),得到中斷響應(yīng)則中斷,還提供公平鎖及非公平鎖。
stringbuffer和stringbuilder區(qū)別
stringbuffer是線程安全,適合多線程操作字符串,stringbuilder是非線程安全的,適合單線程大量操作字符串,在單線程中的性能比StringBuffer高
Java重寫hashCode(),equals()函數(shù)的時機
雖然 a 與 b不是同一個對象,但是你希望無論使用 a 還是 b 都可以從map中取出相同的 value,也就是你會認(rèn)為 a 與 b 的內(nèi)容是相同的,就是當(dāng)把他們作為索引值,或者在 set 中不會重復(fù)出現(xiàn),這些情況適用于重寫他們。重寫equals一定要重寫Hashcode,這是java規(guī)定的。如果不滿足這個條件則map, set等的處理會出現(xiàn)錯誤的。
get()和post()區(qū)別
語義的區(qū)別,設(shè)計不同,get是為請求,post是提交改變服務(wù)器狀態(tài)
1. GET使用URL或Cookie傳參。而POST將數(shù)據(jù)放在BODY中。
2. GET的URL會有長度上的限制,則POST的數(shù)據(jù)則可以非常大。
3. POST比GET安全,因為數(shù)據(jù)在地址欄上不可見。
成員變量的類型
靜態(tài)變量,實例變量,final修飾的常量
七:數(shù)據(jù)結(jié)構(gòu)算法相關(guān)
如何判斷一個鏈表中存在環(huán)
1遍歷做標(biāo)記,2:便利把指針反轉(zhuǎn),如果走到開始就有環(huán),3:雙指針 一個一次走一步,一個一次走兩步
各排序、冒泡排序、二分查找思想原理
二叉樹
問1000壇酒,里面有1壇毒酒,需要多少只老鼠才能判斷出毒酒是哪壇?
都轉(zhuǎn)為二進制 2的10次方為1024,10只老鼠
Linux中查看內(nèi)存使用狀況命令?查看網(wǎng)絡(luò)狀況?
cat/proc/meminfo? free