基礎(chǔ)篇
int與integer的區(qū)別
Integer對象會占用更多的內(nèi)存楷力。Integer是一個對象言蛇,需要存儲對象的元數(shù)據(jù)滑黔。但是int是一個原始類型的數(shù)據(jù)笆包,所以占用的空間更少。
int和Integer的更多區(qū)別:
1.兩個通過new出來的Integer變量比較略荡,結(jié)果為false庵佣。
/**
* 比較兩個new出來的Integer
*/
public class Test {
public static void main(String[] args) {
Integer i = new Integer(200);
Integer j = new Integer(200);
System.out.print(i == j);
//輸出:false
}
}
Integer變量實際上是對一個Integer對象的引用。當new一個Integer時汛兜,實際上是生成一個指針指向此對象巴粪,兩次new Integer生成的是兩個對象,其內(nèi)存地址不同序无,所以兩個new出來的Integer變量不等验毡。
2.非new生成的Integer變量與new Integer()生成的變量比較衡创,結(jié)果為false帝嗡。
/**
* 比較非new生成的Integer變量與new生成的Integer變量
*/
public class Test {
public static void main(String[] args) {
Integer i= new Integer(200);
Integer j = 200;
System.out.print(i == j);
//輸出:false
}
}
因為非new生成的Integer變量指向的是java常量池中的對象,而new Integer()生成的變量指向堆中新建的對象璃氢,兩者在內(nèi)存中的地址不同哟玷。所以 輸出為false。
3.兩個非new生成的Integer對象進行比較,如果兩個變量的值在區(qū)間[-128,127]之間巢寡,比較結(jié)果為true喉脖;否則,結(jié)果為false抑月。
/**
* 比較兩個非new生成的Integer變量
*/
public class Test {
public static void main(String[] args) {
Integer i1 = 127;
Integer ji = 127;
System.out.println(i1 == ji);//輸出:true
Integer i2 = 128;
Integer j2 = 128;
System.out.println(i2 == j2);//輸出:false
}
}
java在編譯Integer i1 = 127時树叽,會翻譯成Integer i1 = Integer.valueOf(127)。java會將[-128,127]之間的數(shù)進行緩存谦絮。Integer i1 = 127時题诵,會將127緩存,Integer j2 = 127時层皱,就直接從緩存中取性锭,不會new了,所以結(jié)果為true叫胖。Integer i2 = 128時草冈,不會將128緩存,Integer j2 = 128時瓮增,會return new Integer(128)怎棱。所以結(jié)果為false。
- Integer變量(無論是否是new生成的)與int變量比較绷跑,只要兩個變量的值是相等的蹄殃,結(jié)果都為true。
/**
* 比較Integer變量與int變量
*/
public class Test {
public static void main(String[] args) {
Integer i1 = 200;
Integer i2 = new Integer(200);
int j = 200;
System.out.println(i1 == j);//輸出:true
System.out.println(i2 == j);//輸出:true
}
}
String你踩、StringBuffer诅岩、StringBuilder區(qū)別
1.三者在執(zhí)行速度方面的比較:StringBuilder > StringBuffer > String
2.String:字符串常量
StringBuffer:字符串變量
StringBuilder:字符串變量
從上面的名字可以看到,String是“字符串常量”带膜,也就是不可改變的對象吩谦。
3.StringBuilder與 StringBuffer:
StringBuilder:線程非安全的
StringBuffer:線程安全的
當我們在字符串緩沖去被多個線程使用是,JVM不能保證StringBuilder的操作是安全的膝藕,雖然他的速度最快式廷,但是可以保證StringBuffer是可以正確操作的。當然大多數(shù)情況下就是我們是在單線程下進行的操作芭挽,所以大多數(shù)情況下是建議用StringBuilder而不用StringBuffer的滑废,就是速度的原因。
總結(jié):
1.如果要操作少量的數(shù)據(jù)用 = String
2.單線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) = StringBuilder
3.多線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) = StringBuffer
什么是內(nèi)部類袜爪?內(nèi)部類的作用
內(nèi)部類可直接訪問外部類的屬性
Java中內(nèi)部類主要分為成員內(nèi)部類蠕趁、局部內(nèi)部類(嵌套在方法和作用域內(nèi))、匿名內(nèi)部類(沒構(gòu)造方法)辛馆、靜態(tài)內(nèi)部類(static修飾的類俺陋,不能使用任何外圍類的非static成員變量和方法, 不依賴外圍類)
進程和線程的區(qū)別
進程是cpu資源分配的最小單位,線程是cpu調(diào)度的最小單位腊状。
進程之間不能共享資源诱咏,而線程共享所在進程的地址空間和其它資源盒发。
一個進程內(nèi)可擁有多個線程遣耍,進程可開啟進程,也可開啟線程凄贩。
一個線程只能屬于一個進程映屋,線程可直接使用同進程的資源,線程依賴于進程而存在硕并。
final,finally秧荆,finalize的區(qū)別
final:修飾類倔毙、成員變量和成員方法,類不可被繼承乙濒,成員變量不可變陕赃,成員方法不可重寫
finally:與try...catch...共同使用,確保無論是否出現(xiàn)異常都能被調(diào)用到
finalize:類的方法,垃圾回收之前會調(diào)用此方法,子類可以重寫finalize()方法實現(xiàn)對資源的回收
Serializable 和Parcelable 的區(qū)別
Serializable Java 序列化接口 在硬盤上讀寫 讀寫過程中有大量臨時變量的生成颁股,內(nèi)部執(zhí)行大量的i/o操作么库,效率很低。
Parcelable Android 序列化接口 效率高 使用麻煩 在內(nèi)存中讀寫(AS有相關(guān)插件 一鍵生成所需方法) 甘有,對象不能保存到磁盤中
靜態(tài)屬性和靜態(tài)方法是否可以被繼承诉儒?是否可以被重寫?以及原因亏掀?
可繼承 不可重寫 而是被隱藏
如果子類里面定義了靜態(tài)方法和屬性忱反,那么這時候父類的靜態(tài)方法或?qū)傩苑Q之為"隱藏"。如果你想要調(diào)用父類的靜態(tài)方法和屬性滤愕,直接通過父類名.方法或變量名完成温算。
成員內(nèi)部類、靜態(tài)內(nèi)部類间影、局部內(nèi)部類和匿名內(nèi)部類的理解注竿,以及項目中的應(yīng)用
Java中內(nèi)部類主要分為成員內(nèi)部類、局部內(nèi)部類(嵌套在方法和作用域內(nèi))魂贬、匿名內(nèi)部類(沒構(gòu)造方法)巩割、靜態(tài)內(nèi)部類(static修飾的類,不能使用任何外圍類的非static成員變量和方法付燥, 不依賴外圍類)
使用內(nèi)部類最吸引人的原因是:每個內(nèi)部類都能獨立地繼承一個(接口的)實現(xiàn)宣谈,所以無論外圍類是否已經(jīng)繼承了某個(接口的)實現(xiàn),對于內(nèi)部類都沒有影響机蔗。
因為Java不支持多繼承蒲祈,支持實現(xiàn)多個接口。但有時候會存在一些使用接口很難解決的問題萝嘁,這個時候我們可以利用內(nèi)部類提供的梆掸、可以繼承多個具體的或者抽象的類的能力來解決這些程序設(shè)計問題⊙姥裕可以這樣說酸钦,接口只是解決了部分問題,而內(nèi)部類使得多重繼承的解決方案變得更加完整咱枉。
哪些情況下的對象會被垃圾回收機制處理掉卑硫?
1.所有實例都沒有活動線程訪問。
2.沒有被其他任何實例訪問的循環(huán)引用實例蚕断。
3.Java 中有不同的引用類型欢伏。判斷實例是否符合垃圾收集的條件都依賴于它的引用類型。
要判斷怎樣的對象是沒用的對象亿乳。這里有2種方法:
1.采用標記計數(shù)的方法:
給內(nèi)存中的對象給打上標記硝拧,對象被引用一次,計數(shù)就加1葛假,引用被釋放了障陶,計數(shù)就減一,當這個計數(shù)為0的時候聊训,這個對象就可以被回收了抱究。當然,這也就引發(fā)了一個問題:循環(huán)引用的對象是無法被識別出來并且被回收的带斑。所以就有了第二種方法:
2.采用根搜索算法:
從一個根出發(fā)鼓寺,搜索所有的可達對象,這樣剩下的那些對象就是需要被回收的
Java中實現(xiàn)多態(tài)的機制是什么勋磕?
方法的重寫Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)
重寫Overriding是父類與子類之間多態(tài)性的一種表現(xiàn)
重載Overloading是一個類中多態(tài)性的一種表現(xiàn).
你對Java反射的理解
JAVA反射機制是在運行狀態(tài)中, 對于任意一個類, 都能夠知道這個類的所有屬性和方法; 對于任意一個對象, 都能夠調(diào)用它的任意一個方法和屬性侄刽。
從對象出發(fā),通過反射(Class類)可以取得取得類的完整信息(類名 Class類型朋凉,所在包州丹、具有的所有方法 Method[]類型、某個方法的完整信息(包括修飾符杂彭、返回值類型墓毒、異常、參數(shù)類型)亲怠、所有屬性 Field[]所计、某個屬性的完整信息、構(gòu)造器 Constructors)团秽,調(diào)用類的屬性或方法自己的總結(jié): 在運行過程中獲得類主胧、對象叭首、方法的所有信息。
String為什么要設(shè)計成不可變的踪栋?
1焙格、字符串池的需求
字符串池是方法區(qū)(Method Area)中的一塊特殊的存儲區(qū)域。當一個字符串已經(jīng)被創(chuàng)建并且該字符串在 池 中夷都,該字符串的引用會立即返回給變量眷唉,而不是重新創(chuàng)建一個字符串再將引用返回給變量。如果字符串不是不可變的囤官,那么改變一個引用(如: string2)的字符串將會導(dǎo)致另一個引用(如: string1)出現(xiàn)臟數(shù)據(jù)冬阳。
2、允許字符串緩存哈希碼
在java中常常會用到字符串的哈希碼党饮,例如: HashMap 肝陪。String的不變性保證哈希碼始終一,因此刑顺,他可以不用擔心變化的出現(xiàn)见坑。 這種方法意味著不必每次使用時都重新計算一次哈希碼——這樣,效率會高很多捏检。
3荞驴、安全
String廣泛的用于java 類中的參數(shù),如:網(wǎng)絡(luò)連接(Network connetion)贯城,打開文件(opening files )等等熊楼。如果String不是不可變的,網(wǎng)絡(luò)連接能犯、文件將會被改變——這將會導(dǎo)致一系列的安全威脅鲫骗。操作的方法本以為連接上了一臺機器,但實際上卻不是踩晶。由于反射中的參數(shù)都是字符串执泰,同樣,也會引起一系列的安全問題渡蜻。
Object類的equal和hashCode方法重寫术吝,為什么?
首先equals與hashcode間的關(guān)系是這樣的:
1茸苇、如果兩個對象相同(即用equals比較返回true)排苍,那么它們的hashCode值一定要相同;
2学密、如果兩個對象的hashCode相同淘衙,它們并不一定相同(即用equals比較返回false)
由于為了提高程序的效率才實現(xiàn)了hashcode方法,先進行hashcode的比較腻暮,如果不同彤守,那沒就不必在進行equals的比較了毯侦,這樣就大大減少了equals比較的次數(shù),這對比需要比較的數(shù)量很大的效率提高是很明顯的
List,Set,Map的區(qū)別
Set是最簡單的一種集合具垫。集合中的對象不按特定的方式排序侈离,并且沒有重復(fù)對象。 Set接口主要實現(xiàn)了兩個實現(xiàn)類:HashSet: HashSet類按照哈希算法來存取集合中的對象做修,存取速度比較快
TreeSet :TreeSet類實現(xiàn)了SortedSet接口霍狰,能夠?qū)现械膶ο筮M行排序抡草。
List的特征是其元素以線性方式存儲饰及,集合中可以存放重復(fù)對象。
ArrayList() : 代表長度可以改變得數(shù)組康震×呛可以對元素進行隨機的訪問,向ArrayList()中插入與刪除元素的速度慢腿短。
LinkedList(): 在實現(xiàn)中采用鏈表數(shù)據(jù)結(jié)構(gòu)屏箍。插入和刪除速度快,訪問速度慢橘忱。
Map 是一種把鍵對象和值對象映射的集合赴魁,它的每一個元素都包含一對鍵對象和值對象。 Map沒有繼承于Collection接口 從Map集合中檢索元素時钝诚,只要給出鍵對象颖御,就會返回對應(yīng)的值對象。
HashMap:Map基于散列表的實現(xiàn)凝颇。插入和查詢“鍵值對”的開銷是固定的潘拱。可以通過構(gòu)造器設(shè)置容量capacity和負載因子load factor拧略,以調(diào)整容器的性能芦岂。
LinkedHashMap: 類似于HashMap,但是迭代遍歷它時垫蛆,取得“鍵值對”的順序是其插入次序禽最,或者是最近最少使用(LRU)的次序。只比HashMap慢一點袱饭。而在迭代訪問時發(fā)而更快弛随,因為它使用鏈表維護內(nèi)部次序。
TreeMap : 基于紅黑樹數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)宁赤。查看“鍵”或“鍵值對”時舀透,它們會被排序(次序由Comparabel或Comparator決定)。TreeMap的特點在 于决左,你得到的結(jié)果是經(jīng)過排序的愕够。TreeMap是唯一的帶有subMap()方法的Map走贪,它可以返回一個子樹。
WeakHashMao :弱鍵(weak key)Map惑芭,Map中使用的對象也被允許釋放: 這是為解決特殊問題設(shè)計的坠狡。如果沒有map之外的引用指向某個“鍵”,則此“鍵”可以被垃圾收集器回收遂跟。
ArrayMap和HashMap的對比
1逃沿、存儲方式不同
HashMap內(nèi)部有一個HashMapEntry<K, V>[]對象,每一個鍵值對都存儲在這個對象里幻锁,當使用put方法添加鍵值對時凯亮,就會new一個HashMapEntry對象,
2哄尔、添加數(shù)據(jù)時擴容時的處理不一樣假消,進行了new操作,重新創(chuàng)建對象岭接,開銷很大富拗。ArrayMap用的是copy數(shù)據(jù),所以效率相對要高鸣戴。
3啃沪、ArrayMap提供了數(shù)組收縮的功能,在clear或remove后窄锅,會重新收縮數(shù)組创千,是否空間
4、ArrayMap采用二分法查找酬滤;
HashMap和HashTable的區(qū)別
HashMap不是線程安全的签餐,效率高一點、方法不是Synchronize的要提供外同步盯串,有containsvalue和containsKey方法氯檐。
hashtable是,線程安全体捏,不允許有null的鍵和值冠摄,效率稍低,方法是是Synchronize的几缭。有contains方法方法河泳。Hashtable 繼承于Dictionary 類
HashMap與HashSet的區(qū)別
hashMap:HashMap實現(xiàn)了Map接口,HashMap儲存鍵值對,使用put()方法將元素放入map中,HashMap中使用鍵對象來計算hashcode值,HashMap比較快,因為是使用唯一的鍵來獲取對象年栓。
HashSet實現(xiàn)了Set接口拆挥,HashSet僅僅存儲對象,使用add()方法將元素放入set中某抓,HashSet使用成員對象來計算hashcode值纸兔,對于兩個對象來說hashcode可能相同惰瓜,所以equals()方法用來判斷對象的相等性,如果兩個對象不同的話汉矿,那么返回false崎坊。HashSet較HashMap來說比較慢。
ArrayList和LinkedList的區(qū)別洲拇,以及應(yīng)用場景
ArrayList是基于數(shù)組實現(xiàn)的奈揍,ArrayList線程不安全。
LinkedList是基于雙鏈表實現(xiàn)的:
使用場景:
(1)如果應(yīng)用程序?qū)Ω鱾€索引位置的元素進行大量的存取或刪除操作赋续,ArrayList對象要遠優(yōu)于LinkedList對象男翰;
(2)如果應(yīng)用程序主要是對列表進行循環(huán),并且循環(huán)時候進行插入或者刪除操作蚕捉,LinkedList對象要遠優(yōu)于ArrayList對象奏篙;
數(shù)組和鏈表的區(qū)別
數(shù)組:是將元素在內(nèi)存中連續(xù)存儲的柴淘;它的優(yōu)點:因為數(shù)據(jù)是連續(xù)存儲的迫淹,內(nèi)存地址連續(xù),所以在查找數(shù)據(jù)的時候效率比較高为严;它的缺點:在存儲之前敛熬,我們需要申請一塊連續(xù)的內(nèi)存空間,并且在編譯的時候就必須確定好它的空間的大小第股。在運行的時候空間的大小是無法隨著你的需要進行增加和減少而改變的应民,當數(shù)據(jù)兩比較大的時候,有可能會出現(xiàn)越界的情況夕吻,數(shù)據(jù)比較小的時候诲锹,又有可能會浪費掉內(nèi)存空間。在改變數(shù)據(jù)個數(shù)時涉馅,增加归园、插入、刪除數(shù)據(jù)效率比較低
鏈表:是動態(tài)申請內(nèi)存空間稚矿,不需要像數(shù)組需要提前申請好內(nèi)存的大小庸诱,鏈表只需在用的時候申請就可以,根據(jù)需要來動態(tài)申請或者刪除內(nèi)存空間晤揣,對于數(shù)據(jù)增加和刪除以及插入比數(shù)組靈活桥爽。還有就是鏈表中數(shù)據(jù)在內(nèi)存中可以在任意的位置,通過應(yīng)用來關(guān)聯(lián)數(shù)據(jù)(就是通過存在元素的指針來聯(lián)系)
run()和start()方法區(qū)別
start()方法被用來啟動新創(chuàng)建的線程昧识,而且start()內(nèi)部調(diào)用了run()方法钠四,這和直接調(diào)用run()方法的效果不一樣。當你調(diào)用run()方法的時候跪楞,只會是在原來的線程中調(diào)用缀去,沒有新的線程啟動环疼,start()方法才會啟動新線程。
在Java中wait和seelp方法的不同
Java程序中wait 和 sleep都會造成某種形式的暫停朵耕,它們可以滿足不同的需要炫隶。wait()方法用于線程間通信,如果等待條件為真且其它線程被喚醒時它會釋放鎖阎曹,而sleep()方法僅僅釋放CPU資源或者讓當前線程停止執(zhí)行一段時間伪阶,但不會釋放鎖。
如何實現(xiàn)線程同步处嫌?
1栅贴、synchronized關(guān)鍵字修改的方法。
2熏迹、synchronized關(guān)鍵字修飾的語句塊
3檐薯、使用特殊域變量(volatile)實現(xiàn)線程同步
談?wù)剬ynchronized關(guān)鍵字,類鎖注暗,方法鎖坛缕,重入鎖的理解
java的對象鎖和類鎖:java的對象鎖和類鎖在鎖的概念上基本上和內(nèi)置鎖是一致的,但是捆昏,兩個鎖實際是有很大的區(qū)別的赚楚,對象鎖是用于對象實例方法,或者一個對象實例上的骗卜,類鎖是用于類的靜態(tài)方法或者一個類的class對象上的宠页。我們知道,類的對象實例可以有很多個寇仓,但是每個類只有一個class對象举户,所以不同對象實例的對象鎖是互不干擾的,但是每個類只有一個類鎖遍烦。但是有一點必須注意的是俭嘁,其實類鎖只是一個概念上的東西,并不是真實存在的乳愉,它只是用來幫助我們理解鎖定實例方法和靜態(tài)方法的區(qū)別的
synchronized 和volatile 關(guān)鍵字的區(qū)別
1.volatile本質(zhì)是在告訴jvm當前變量在寄存器(工作內(nèi)存)中的值是不確定的兄淫,需要從主存中讀取蔓姚;synchronized則是鎖定當前變量捕虽,只有當前線程可以訪問該變量,其他線程被阻塞住坡脐。
2.volatile僅能使用在變量級別泄私;synchronized則可以使用在變量、方法、和類級別的
3.volatile僅能實現(xiàn)變量的修改可見性晌端,不能保證原子性捅暴;而synchronized則可以保證變量的修改可見性和原子性
4.volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞咧纠。
5.volatile標記的變量不會被編譯器優(yōu)化蓬痒;synchronized標記的變量可以被編譯器優(yōu)化
死鎖的四個必要條件?
死鎖產(chǎn)生的原因
- 系統(tǒng)資源的競爭系統(tǒng)資源的競爭導(dǎo)致系統(tǒng)資源不足漆羔,以及資源分配不當梧奢,導(dǎo)致死鎖。
- 進程運行推進順序不合適
互斥條件:一個資源每次只能被一個進程使用演痒,即在一段時間內(nèi)某 資源僅為一個進程所占有亲轨。此時若有其他進程請求該資源,則請求進程只能等待鸟顺。
請求與保持條件:進程已經(jīng)保持了至少一個資源惦蚊,但又提出了新的資源請求,而該資源 已被其他進程占有讯嫂,此時請求進程被阻塞蹦锋,但對自己已獲得的資源保持不放。
不可剝奪條件:進程所獲得的資源在未使用完畢之前端姚,不能被其他進程強行奪走晕粪,即只能 由獲得該資源的進程自己來釋放(只能是主動釋放)挤悉。
循環(huán)等待條件: 若干進程間形成首尾相接循環(huán)等待資源的關(guān)系
這四個條件是死鎖的必要條件渐裸,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立装悲,而只要上述條件之一不滿足昏鹃,就不會發(fā)生死鎖。
死鎖避免的基本思想:
系統(tǒng)對進程發(fā)出每一個系統(tǒng)能夠滿足的資源申請進行動態(tài)檢查,并根據(jù)檢查結(jié)果決定是否分配資源,如果分配后系統(tǒng)可能發(fā)生死鎖,則不予分配,否則予以分配诀诊。這是一種保證系統(tǒng)不進入死鎖狀態(tài)的動態(tài)策略。
理解了死鎖的原因,尤其是產(chǎn)生死鎖的四個必要條件悬蔽,就可以最大可能地避免棒仍、預(yù)防和解除死鎖。所以抡蛙,在系統(tǒng)設(shè)計护昧、進程調(diào)度等方面注意如何讓這四個必要條件不成立,如何確定資源的合理分配算法粗截,避免進程永久占據(jù)系統(tǒng)資源惋耙。此外,也要防止進程在處于等待狀態(tài)的情況下占用資源。因此绽榛,對資源的分配要給予合理的規(guī)劃湿酸。
死鎖避免和死鎖預(yù)防的區(qū)別:
死鎖預(yù)防是設(shè)法至少破壞產(chǎn)生死鎖的四個必要條件之一,嚴格的防止死鎖的出現(xiàn),而死鎖避免則不那么嚴格的限制產(chǎn)生死鎖的必要條件的存在,因為即使死鎖的必要條件存在,也不一定發(fā)生死鎖。死鎖避免是在系統(tǒng)運行過程中注意避免死鎖的最終發(fā)生灭美。
有三個線程T1推溃,T2,T3届腐,怎么確保它們按順序執(zhí)行美莫?
在多線程中有多種方法讓線程按特定順序執(zhí)行,你可以用線程類的join()方法在一個線程中啟動另一個線程梯捕,另外一個線程完成該線程繼續(xù)執(zhí)行厢呵。為了確保三個線程的順序你應(yīng)該先啟動最后一個(T3調(diào)用T2,T2調(diào)用T1)傀顾,這樣T1就會先完成而T3最后完成襟铭。
Binder的工作機制
直觀來說,Binder是Android中的一個類短曾,它實現(xiàn)了IBinder接口寒砖,從IPC的角度來說,Binder是Android中的一種跨進程通信的一種方式嫉拐,同時還可以理解為是一種虛擬的物理設(shè)備哩都,它的設(shè)備驅(qū)動是/dev/binder/。從Framework角度來說婉徘,Binder是ServiceManager的橋梁漠嵌。從應(yīng)用層來說,Binder是客戶端和服務(wù)端進行通信的媒介盖呼。
我們先來了解一下這個類中每個方法的含義:
DESCRIPTOR:Binder的唯一標識儒鹿,一般用于當前Binder的類名表示。
asInterface(android.os.IBinder obj):用于將服務(wù)端的Binder對象轉(zhuǎn)換成客戶端所需的AIDL接口類型的對象几晤,這種轉(zhuǎn)化過程是區(qū)分進程的约炎,如果客戶端和服務(wù)端位于同一個進程,那么這個方法返回的是服務(wù)端的stub對象本身蟹瘾,否則返回的是系統(tǒng)封裝后的Stub.proxy對象圾浅。
asBinder():用于返回當前Binder對象。
onTransact:該方法運行在服務(wù)端的Binder線程池中憾朴,當客戶端發(fā)起跨進程通信請求的時候狸捕,遠程請求通過系統(tǒng)底層封裝后交給該方法處理。注意這個方法public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)伊脓,服務(wù)端通過code可以確定客戶端所請求的目標方法是什么府寒,接著從data中取出目標方法所需的參數(shù)魁衙,然后執(zhí)行目標方法。當目標方法執(zhí)行完畢后株搔,就像reply中寫入返回值剖淀。這個方法的執(zhí)行過程就是這樣的。如果這個方法返回false纤房,客戶端是會請求失敗的纵隔,所以我們可以在這個方法中做一些安全驗證。
Binder的工作機制但是要注意一些問題:1炮姨、當客戶端發(fā)起請求時捌刮,由于當前線程會被掛起,直到服務(wù)端返回數(shù)據(jù)舒岸,如果這個遠程方法很耗時的話绅作,那么是不能夠在UI線程,也就是主線程中發(fā)起這個遠程請求的蛾派。
2俄认、由于Service的Binder方法運行在線程池中,所以Binder方法不管是耗時還是不耗時都應(yīng)該采用同步的方式洪乍,因為它已經(jīng)運行在一個線程中了眯杏。
抽象類和接口區(qū)別
抽象類(abstract class):
使用abstract修飾符修飾的類。官方點的定義就是:如果一個類沒有包含足夠多的信息來描述一個具體的對象壳澳,這樣的類就是抽象類岂贩。實際點來說,一個抽象類不能實例化巷波,因為“沒有包含足夠多的信息來描述一個具體的對象”萎津。但終歸屬于類,所以仍然擁有普通類一樣的定義褥紫。依然可以在類的實體(直白點就是能在{}里面)定義成員變量姜性,成員方法,構(gòu)造方法等髓考。那么可能初學者會問:既然不能實例化,那么在類里面定義成員方法弃酌,成員變量有什么用氨菇。抽象類在實際應(yīng)用中,更多的是因為類中有抽象方法妓湘。抽象方法:只聲明查蓉,不實現(xiàn)。具體的實現(xiàn)由繼承它的子類來實現(xiàn)榜贴。實際點就是:被abstract修飾的方法豌研,只有方法名沒有方法實現(xiàn)妹田,具體的實現(xiàn)要由子類實現(xiàn)。方法名后面直接跟一個分號鹃共,而不是花括號鬼佣。例如:public abstract int A();一個類中含有抽象方法(被abstract修飾),那么這個類必須被聲明為抽象類(被abstract修飾)霜浴。
接口(interface):
官方定義:接口在java中是一個抽象類型晶衷,是抽象方法的集合。
一個類通過繼承接口的方式阴孟,從而繼承接口的抽象方法晌纫。
從定義上看,接口是個集合永丝,并不是類锹漱。類描述了屬性和方法,而接口只包含方法(未實現(xiàn)的方法)慕嚷。
接口和抽象類一樣不能被實例化凌蔬,因為不是類。但是接口可以被實現(xiàn)(使用 implements 關(guān)鍵字)闯冷。
實現(xiàn)某個接口的類必須在類中實現(xiàn)該接口的全部方法砂心。
雖然接口內(nèi)的方法都是抽象的(和抽象方法很像,沒有實現(xiàn))但是不需要abstract關(guān)鍵字蛇耀。
接口中沒有構(gòu)造方式(因為接口不是類)接口中的方法必須是抽象的(不能實現(xiàn))接口中除了static辩诞、final變量,不能有其他變量接口支持多繼承(一個類可以實現(xiàn)多個接口)
抽象類和接口的區(qū)別:
默認的方法實現(xiàn) 抽象類可以有默認的方法實現(xiàn)完全是抽象的纺涤。接口根本不存在方法的實現(xiàn)译暂。
抽象類中可以有已經(jīng)實現(xiàn)了的方法,也可以有被abstract修飾的方法(抽象方法)撩炊,因為存在抽象方法外永,所以該類必須是抽象類。但是接口要求只能包含抽象方法拧咳,抽象方法是指沒有實現(xiàn)的方法伯顶。所以就不能像抽象類那么無賴了,接口就根本不能存在方法的實現(xiàn)骆膝。實現(xiàn) 抽象類使用extends關(guān)鍵字來繼承抽象類祭衩。如果子類不是抽象類的話,它需要提供抽象類中所有聲明的方法的實現(xiàn)阅签。子類使用關(guān)鍵字implements來實現(xiàn)接口掐暮。它需要提供接口中所有聲明的方法的實現(xiàn)。抽象類雖然不能實例化來使用政钟,但是可以被繼承路克,讓子類來具體實現(xiàn)父類的所有抽象方法樟结。有點老子沒完成的夢想交給兒子來完成,但是如果子類將抽象方法沒有全部實現(xiàn)精算,就必須把自己也修飾成抽象類瓢宦,交于繼承它的子類來完成實現(xiàn)。就相當于殖妇,兒子能力不夠也沒完成老爹的夢想刁笙,現(xiàn)在兒子等著再生兒子(被繼承),然后讓孫子去完成谦趣。以此類推疲吸,知道沒有抽象函數(shù)。接口的實現(xiàn)前鹅,通過implements關(guān)鍵字摘悴。實現(xiàn)該接口的類,必須把接口中的所有方法給實現(xiàn)舰绘。不能再推給下一代蹂喻。和抽象類相比,抽象類是將夢想傳給家族捂寿,一代一代去完成口四。那么接口就是掌門人找大師兄來完成幫派的鴻星偉業(yè),這時候就只有一次希望秦陋,要么有能力就實現(xiàn)蔓彩,沒能力就不要接。抽象類可以有構(gòu)造器驳概,而接口不能有構(gòu)造器這個原因很簡單赤嚼,我們回到雙方的定義上來,抽象類再怎么流氓無賴也好顺又,終究是屬于類更卒,就天生享有類的所有特性(但是不能實例化),當然包括類的構(gòu)造方法稚照,也就是構(gòu)造器蹂空。但是接口是所有抽象方法的集合,注意锐锣,是集合腌闯,不是類。當然沒有構(gòu)造方法一說雕憔,更別提什么構(gòu)造器了。抽象方法可以有public糖声、protected和default這些修飾符 接口方法默認修飾符是public斤彼。你不可以使用其它修飾符分瘦。抽象類的目的就是被繼承,抽象方法就是為了被重寫琉苇,所以肯定不能用private修飾符嘲玫,肯定是可以用public的。但是protected和default也是可以的并扇。接口就有且只有一個public修飾去团。(是不是感覺抽象類像小兒子各種耍無賴,接口就像私生子穷蛹,說什么只能是什么)抽象類在java語言中所表示的是一種繼承關(guān)系土陪,一個子類只能存在一個父類,但是可以存在多個接口肴熏。
java在類的繼承上并沒有多繼承鬼雀。抽象類屬于類,所以可以被繼承蛙吏。但子類只能繼承一個父類源哩。java為了實現(xiàn)多繼承,使用了接口鸦做。一個類可以實現(xiàn)多個接口励烦。繼承就好比生了孩子,只能有一個爹泼诱,但是這個孩子可以學語文坛掠,學數(shù)學,學英語等等很多東西坷檩,而語文却音、數(shù)學、英語就相當于接口矢炼∠灯埃總的來說,因為java中抽象類只有單繼承句灌,接口就可以實現(xiàn)多繼承夷陋。抽象方法比接口速度要快接口是稍微有點慢的,因為它需要時間去尋找在類中實現(xiàn)的方法胰锌。記住抽象方法是小兒子骗绕,從小吃的好所以跑的快,接口是私生子资昧,從小日子苦酬土,營養(yǎng)不良。如果你往抽象類中添加新的方法格带,你可以給它提供默認的實現(xiàn)撤缴。因此你不需要改變你現(xiàn)在的代碼刹枉。 如果你往接口中添加方法,那么你必須改變實現(xiàn)該接口的類屈呕。
抽象類可以有一些非抽象方法的存在微宝,這些方法被稱為默認實現(xiàn)。如果添加一個默認實現(xiàn)方法(不能是抽象方法)虎眨,就不需要在子類中去實現(xiàn)蟋软,所以繼承這個抽象類的子類無須改動。但是嗽桩,接口中只能添加抽象方法岳守,當你添加了抽象方法,實現(xiàn)該接口的類就必須實現(xiàn)這個新添加的方法涤躲。因為棺耍,定義中說的很清楚,接口的實現(xiàn)必須實現(xiàn)所有的方法种樱。所有蒙袍,當然包括新添加的方法。
父類的靜態(tài)方法能不能被子類重寫嫩挤?
答案是不能害幅。
因為靜態(tài)方法從程序開始運行后就已經(jīng)分配了內(nèi)存,也就是說已經(jīng)寫死了岂昭。所有引用到該方法的對象(父類的對象也好子類的對象也好)所指向的都是同一塊內(nèi)存中的數(shù)據(jù)以现,也就是該靜態(tài)方法,并沒有重寫這一說法约啊。
java虛擬機的工作原理
參考文章:https://www.cnblogs.com/lishun1005/p/6019678.html
java虛擬機和Dalvik虛擬機的區(qū)別
參考文章:http://www.reibang.com/p/923aebd31b65
哪些情況下的對象會被垃圾回收機制處理掉邑遏?
參考文章:http://www.reibang.com/p/5261a62e4d29
http://www.reibang.com/p/778dd3848196
造成內(nèi)存泄漏的原因探索:
參考文章:http://www.reibang.com/p/3ea9e9dfdb28
常用排序算法(必須會手寫)
參考文章:http://www.reibang.com/p/b06f95178d49
現(xiàn)有線程 T1、T2 和 T3恰矩。你如何確保 T2 線程在 T1 之后執(zhí)行记盒,并且 T3 線程在 T2 之后執(zhí)行?
這個線程面試題通常在第一輪面試或電話面試時被問到外傅,這道多線程問題為了測試面試者是否熟悉 join 方法的概念纪吮。答案也非常簡單——可以用 Thread 類的 join 方法實現(xiàn)這一效果。
Java 中新的 Lock 接口相對于同步代碼塊(synchronized block)有什么優(yōu)勢萎胰?如果讓你實現(xiàn)一個高性能緩存碾盟,支持并發(fā)讀取和單一寫入,你如何保證數(shù)據(jù)完整性技竟?
多線程和并發(fā)編程中使用 lock 接口的最大優(yōu)勢是它為讀和寫提供兩個單獨的鎖冰肴,可以讓你構(gòu)建高性能數(shù)據(jù)結(jié)構(gòu),比如 ConcurrentHashMap 和條件阻塞。
這道 Java 線程面試題越來越多見嚼沿,而且隨后的面試題都基于面試者對這道題的回答估盘。
我強烈建議在任何 Java 多線程面試前都要多看看有關(guān)鎖的知識瓷患,因為如今電子交易系統(tǒng)的客戶端和數(shù)據(jù)交互中骡尽,鎖被頻繁使用來構(gòu)建緩存。
Java 中 wait 和 sleep 方法有什么區(qū)別擅编?
兩者主要的區(qū)別就是等待釋放鎖和監(jiān)視器攀细。sleep方法在等待時不會釋放任何鎖或監(jiān)視器。wait 方法多用于線程間通信爱态,而 sleep 只是在執(zhí)行時暫停谭贪。可以看我另一篇有關(guān)Java 中 wait 和 sleep的文章锦担。
Java 中你如何喚醒阻塞線程俭识?
這是有關(guān)線程的一個很狡猾的問題。有很多原因會導(dǎo)致阻塞洞渔,如果是 IO 阻塞套媚,我認為沒有方式可以中斷線程(如果有的話請告訴我)。另一方面磁椒,如果線程阻塞是由于調(diào)用了 wait()堤瘤,sleep() 或 join() 方法,你可以中斷線程浆熔,通過拋出 InterruptedException 異常來喚醒該線程本辐。可以看這篇文章了解有關(guān)處理阻塞線程的知識Java 中如何處理阻塞方法医增。
字節(jié)流與字符流的區(qū)別
字節(jié)流和字符流使用是非常相似的慎皱,字節(jié)流在操作的時候本身是不會用到緩沖區(qū)(內(nèi)存)的,是與文件本身直接操作的叶骨,而字符流在操作的時候是使用到緩沖區(qū)的茫多。
字節(jié)流在操作文件時,即使不關(guān)閉資源(close 方法)邓萨,文件也能輸出地梨,
但是如果字符流不使用 close 方法的話,則不會輸出任何內(nèi)容缔恳,說明字符流用的是緩沖區(qū)宝剖,并且可以使用 flush 方法強制進行刷新緩沖區(qū),這時才能在不 close 的情況下輸出內(nèi)容歉甚。
Java集合類框架的基本接口有哪些万细?
Java集合類里面最基本的接口有:
Collection:代表一組對象,每一個對象都是它的子元素。
Set:不包含重復(fù)元素的Collection赖钞。
List:有順序的Collection腰素,并且可以包含重復(fù)元素。
Map:可以把鍵(key)映射到值(value)的對象雪营,鍵不能重復(fù)弓千。
&和&&的區(qū)別
&是位運算符,表示按位與運算献起,&&是邏輯運算符洋访,表示邏輯與(and)。
判斷條件a&&b谴餐,如果a是false就不會判斷b姻政,但是a&b,a岂嗓、b都會判斷汁展。
&&相當于有阻斷作用。
heap(堆)和stack(棧)有什么區(qū)別
棧是后進先出的線性表結(jié)構(gòu)厌殉,存取速度比堆快食绿。創(chuàng)建對象的時候new一個對象,引用存在棧上具體的內(nèi)容存在堆上年枕。
棧與堆都是Java用來在RAM中存放數(shù)據(jù)的地方炫欺。與C++不同,Java自動管理棧和堆熏兄,程序員不能直接地設(shè)置椘仿澹或堆。
Java的堆是一個運行時數(shù)據(jù)區(qū),類的對象從中分配空間摩桶。這些對象通過new指令建立桥状,它們不需要程序代碼來顯式的釋放。堆是由垃圾回收來負責的硝清,
堆的優(yōu)勢是可以動態(tài)地分配內(nèi)存大小辅斟,生存期也不必事先告訴編譯器,因為它是在運行時動態(tài)分配內(nèi)存的芦拿,Java的垃圾收集器會自動收走這些不再使用的數(shù)據(jù)士飒。但缺點是,
由于要在運行時動態(tài)分配內(nèi)存蔗崎,存取速度較慢酵幕。
棧的優(yōu)勢是,存取速度比堆要快缓苛,僅次于寄存器芳撒,棧數(shù)據(jù)可以共享。
但缺點是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的笔刹,缺乏靈活性芥备。棧中主要存放一些基本類型的變量(,int, short, long, byte, float, double, boolean, char)和對象句柄。
棧有一個很重要的特殊性舌菜,就是存在棧中的數(shù)據(jù)可以共享萌壳。假設(shè)我們同時定義:
int a = 3;
int b = 3;
編譯器先處理int a = 3酷师;首先它會在棧中創(chuàng)建一個變量為a的引用讶凉,然后查找棧中是否有3這個值,如果沒找到山孔,就將3存放進來,然后將a指向3荷憋。接著處理int b = 3台颠;在創(chuàng)建完b的引用變量后,
因為在棧中已經(jīng)有3這個值勒庄,便將b直接指向3眉撵。這樣恶迈,就出現(xiàn)了a與b同時均指向3的情況。
這時,如果再令a=4铃慷;那么編譯器會重新搜索棧中是否有4值,如果沒有藕施,則將4存放進來摩幔,并令a指向4;如果已經(jīng)有了铐尚,則直接將a指向這個地址拨脉。因此a值的改變不會影響到b的值。
要注意這種數(shù)據(jù)的共享與兩個對象的引用同時指向一個對象的這種共享是不同的宣增,因為這種情況a的修改并不會影響到b, 它是由編譯器完成的玫膀,它有利于節(jié)省空間。而一個對象引用變量修改了這個對象的內(nèi)部狀態(tài)爹脾,會影響到另一個對象引用變量帖旨。
String是一個特殊的包裝類數(shù)據(jù)×榉粒可以用:
String str = new String("abc");
String str = "abc";
兩種的形式來創(chuàng)建解阅,第一種是用new()來新建對象的,它會在存放于堆中闷串。每調(diào)用一次就會創(chuàng)建一個新的對象瓮钥。
而第二種是先在棧中創(chuàng)建一個對String類的對象引用變量str,然后查找棧中有沒有存放"abc",如果沒有碉熄,則將"abc"存放進棧桨武,并令str指向”abc”,如果已經(jīng)有”abc” 則直接令str指向“abc”锈津。
比較類里面的數(shù)值是否相等時呀酸,用equals()方法;當測試兩個包裝類的引用是否指向同一個對象時琼梆,用==性誉,下面用例子說明上面的理論。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一個對象的茎杂。
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的對象错览。每一次生成一個。
因此用第一種方式創(chuàng)建多個”abc”字符串,在內(nèi)存中其實只存在一個對象而已. 這種寫法有利與節(jié)省內(nèi)存空間. 同時它可以在一定程度上提高程序的運行速度煌往,因為JVM會自動根據(jù)棧中數(shù)據(jù)的實際情況來決定是否有必要創(chuàng)建新對象倾哺。而對于String str = new String("abc");的代碼刽脖,則一概在堆中創(chuàng)建新對象羞海,而不管其字符串值是否相等,是否有必要創(chuàng)建新對象曲管,從而加重了程序的負擔却邓。
另一方面, 要注意: 我們在使用諸如String str = "abc";的格式定義類時院水,總是想當然地認為腊徙,創(chuàng)建了String類的對象str。擔心陷阱衙耕!對象可能并沒有被創(chuàng)建昧穿!而可能只是指向一個先前已經(jīng)創(chuàng)建的對象。只有通過new()方法才能保證每次都創(chuàng)建一個新的對象橙喘。
由于String類的immutable性質(zhì)时鸵,當String變量需要經(jīng)常變換其值時,應(yīng)該考慮使用StringBuffer類厅瞎,以提高程序效率饰潜。
2.2申請后系統(tǒng)的響應(yīng)
棧:只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存和簸,否則將報異常提示棧溢出彭雾。
堆: 首先應(yīng)該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表,當系統(tǒng)收到程序的申請時锁保,會遍歷該鏈表薯酝,尋找第一個空間大于所申請空間的堆結(jié)點半沽,然后將該結(jié)點從空閑 結(jié)點鏈表中刪除,
并將該結(jié)點的空間分配給程序吴菠,另外者填,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小做葵,這樣占哟,代碼中的delete語句才能正確的釋放本內(nèi)存空間。
另外酿矢,由于找到的堆結(jié)點的大小不一定正好等于申請的大小榨乎,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中。
2.3申請大小的限制
棧:在Windows下,棧是向低地址擴展的數(shù)據(jù)結(jié)構(gòu)瘫筐,是一塊連續(xù)的內(nèi)存的區(qū)域蜜暑。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在WINDOWS下严肪,棧的大小是2M
(也可能是1M史煎,它是一個編譯時就確定的常數(shù)),如果申請的空間超過棧的剩余空間時驳糯,將提示overflow。因此氢橙,能從棧獲得的空間較小酝枢。
堆:堆是向高地址擴展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域悍手。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的帘睦,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址坦康。
堆的大小受限于計算機系統(tǒng)中有效的虛擬內(nèi)存竣付。由此可見,堆獲得的空間比較靈活滞欠,也比較大古胆。
2.4申請效率的比較:
棧由系統(tǒng)自動分配,速度較快筛璧。但程序員是無法控制的逸绎。
堆是由new分配的內(nèi)存,一般速度比較慢夭谤,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便.
另外棺牧,在WINDOWS下,最好的方式是用VirtualAlloc分配內(nèi)存朗儒,他不是在堆颊乘,也不是在棧是直接在進程的地址空間中保留一快內(nèi)存参淹,雖然用起來最不方便。但是速度快乏悄,也最靈活浙值。
2.5堆和棧中的存儲內(nèi)容
棧:在函數(shù)調(diào)用時,第一個進棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語句的下一條可執(zhí)行語句)的地址纲爸,然后是函數(shù)的各個參數(shù)亥鸠,在大多數(shù)的C編譯器中,
參數(shù)是由右往左入棧的识啦,然后是函數(shù)中的局部變量负蚊。注意靜態(tài)變量是不入棧的。當本次函數(shù)調(diào)用結(jié)束后颓哮,局部變量先出棧家妆,然后是參數(shù),最后棧頂指針指向最開始存的地址冕茅,
也就是主函數(shù)中的下一條指令伤极,程序由該點繼續(xù)運行。
堆:一般是在堆的頭部用一個字節(jié)存放堆的大小姨伤。堆中的具體內(nèi)容有程序員安排哨坪。
2.6存取效率的比較
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運行時刻賦值的;
而bbbbbbbbbbb是在編譯時就確定的乍楚;
但是当编,在以后的存取中,在棧上的數(shù)組比指針所指向的字符串(例如堆)快徒溪。
堆和棧的區(qū)別可以用如下的比喻來看出:
使用棧就象我們?nèi)ワ堭^里吃飯忿偷,只管點菜(發(fā)出申請)、付錢臊泌、和吃(使用)鲤桥,吃飽了就走,不必理會切菜渠概、洗菜等準備工作和洗碗茶凳、刷鍋等掃尾工作,他的好處是快捷高氮,但是自由度小慧妄。
使用堆就象是自己動手做喜歡吃的菜肴,比較麻煩剪芍,但是比較符合自己的口味塞淹,而且自由度大。