www.itlanbao.com 本網站裏面分享不少Android特效,更多的面試資料在IT藍豹資訊部分 ,但願可以給你幫助,歡迎到IT藍豹上互相學習。html
|
ArrayListjava |
Vectorandroid |
LinkedList程序員 |
實現原理web |
數組面試 |
數組算法 |
雙向鏈表數據庫 |
線程安全編程 |
否設計模式 |
是 |
否 |
優勢 |
1.數組實現優於遍歷 |
1.數組實現優於遍歷 |
1.節點的增刪無需對象的重建 |
缺點 |
1.非線程安全 |
1.數組中未使用的元素形成空間的浪費 |
1.遍歷效率較低 |
擴容 |
0.5倍增量 |
1倍增量 |
按需增刪 |
使用場景 |
1.無線程的要求。 |
1.有線程安全的要求 |
增刪場景較多的時候 |
11.int與Integer的區別
|
int |
Integer |
類型 |
基本類型 |
複合類型 |
默認值 |
0 |
null |
存儲 |
棧(局部變量) |
堆上(只能經過new建立) |
方法 |
基本類型無方法 |
有 |
速度 |
快(棧上 的操做相對快) |
慢 |
泛型支持 |
否(java中的泛型不支持,C++中的模板支持) |
支持 |
容器類支持 |
否(直接使用一般會進行裝箱操做) |
支持 |
存在乎義 |
1.歷史緣由(順延C/C++中存在) |
基本類型int的包裝類 |
Checked Exception:在編譯時就可以被Java編譯器所檢測到的。
UncheckedException:則是編譯時,java編譯器不能檢查到。
|
RuntimeException |
普通Exception |
Error |
受控異常 |
否 |
是 |
否 |
產生緣由 |
開發者的編程錯誤 |
因爲外界環境所限, |
Java運行時的系統錯誤,資源耗盡,是一種嚴重的, |
例子 |
NullPointerException |
ClassNotFoundException |
VirtualMachineError |
final:關鍵字,表不變
修飾:
· 方法:方法不可Override
· 類:不可被繼承
· 基本類型量:常量,值不可變
· 符合類型量:引用不可變,即引用的值不可變
[java] view plaincopy
1. final Object o1 = new Object();
2. o1 = new Object();
finally:關鍵字,Java異常處理機制的一部分,在異常發生時,用來提供一個必要的清理的機會。
finalize:Object類的方法(參考自百度百科)
意義:Java技術容許使用finalize()方法在垃圾回收器將對象回收以前,作一些必要的清理操做。
調用前提:這個對象肯定沒有被引用到。
工做原理:
· 垃圾收集器準備好釋放對象佔用的空間。
· 首先調用其finalize方法。
· 下一次垃圾收集過程當中,真正回收內存。
不肯定性:
· finalize的執行時間是不缺定的。
· 一個對象引用另外一個對象,並不能保證finalize的方法按照特定的執行順序。
|
Override |
Overload |
簽名+返回值 |
相同 |
方法名相同,簽名不一樣 |
關係 |
父子類繼承關係 |
一般是同一類層次中 |
識別 |
運行時多態 |
編譯時多態 |
修飾符限制 |
非private |
無特別 |
異常關係 |
子類方法不能拋出被父類方法更多的異常 |
無特別 |
可見性關係 |
子類不能比父類訪問權限更窄 |
無特別 |
Collection:接口,集合類的接口,一個契約,提供了集合基本的大小,添加,清除,遍歷方法等。
Collections:工具類,提供了不少靜態方法,給集合提供一些查詢,比較,排序,交換,線程安全化等方法。
package com.jue.test;
public class TestMain {
public static void main(String[] args) {
Integer i1 = 1;
Integer i11 = 1;
System.out.println(i1 == i11);
Integer i2 = 200;
Integer i22 = 200;
System.out.println(i2 == i22);
}
}
結果 :True,false
分析:反編譯結果爲 Integer i1 = Integer.valueOf(1);
能夠看出,對於Integer i = 1;編譯器作了額外的處理,即Integer.valueof();能夠看出Integer對於必定 範圍內的數字從Cache中取得,對於額外的,調用new建立。
故能夠知道Integer的大小,默認是從-128到127,對於這個範圍內的數組作了緩存的處理。 對於額外的,調用new建立
|
wait |
sleep |
所屬類 |
Object |
Thread |
意義 |
讓線程掛起 |
讓線程休眠指定的時間 |
釋放鎖 |
是 |
否(這個跟鎖原本就沒有關係) |
恢復 |
1.有參:wait指定時間 |
1.根據參數長度自動恢復。 |
使用限制 |
wait,notify必須持有當前對象鎖的狀況下調用 |
無特別 |
拋出異常 |
否 |
是 |
靜態方法 |
否 |
是 |
HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在於HashMap容許空(null)鍵值(key),因爲非線程安全,效率上可能高於Hashtable。
HashMap容許將null做爲一個entry的key或者value,而Hashtable不容許。
HashMap把Hashtable的contains方法去掉了,改爲containsvalue和containsKey。由於contains方法容易讓人引發誤解。
整體來講設計模式分爲三大類:
建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行爲型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
其實還有兩類:併發型模式和線程池模式。用一個圖片來總體描述一下:
http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
首先,建立兩者的共同接口:
[java] view plaincopy
1. public interface Sender {
2. public void Send();
3. }
其次,建立實現類:
[java] view plaincopy
1. public class MailSender implements Sender {
2. @Override
3. public void Send() {
4. System.out.println("this is mailsender!");
5. }
6. }
[java] view plaincopy
1. public class SmsSender implements Sender {
2.
3. @Override
4. public void Send() {
5. System.out.println("this is sms sender!");
6. }
7. }
最後,建工廠類:
[java] view plaincopy
1. public class SendFactory {
2.
3. public Sender produce(String type) {
4. if ("mail".equals(type)) {
5. return new MailSender();
6. } else if ("sms".equals(type)) {
7. return new SmsSender();
8. } else {
9. System.out.println("請輸入正確的類型!");
10. return null;
11. }
12. }
13. }
咱們來測試下:
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produce("sms");
6. sender.Send();
7. }
8. }
輸出:this is sms sender!
a、多個工廠方法模式,是對普通工廠方法模式的改進,在普通工廠方法模式中,若是傳遞的字符串出錯,則不能正確建立對象,而多個工廠方法模式是提供多個工廠方法,分別建立對象。關係圖:
將上面的代碼作下修改,改動下SendFactory類就行,以下:
[java] view plaincopypublic class SendFactory {
public Sender produceMail(){
1. return new MailSender();
2. }
3.
4. public Sender produceSms(){
5. return new SmsSender();
6. }
7. }
測試類以下:
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produceMail();
6. sender.Send();
7. }
8. }
輸出:this is mailsender!
b、靜態工廠方法模式,將上面的多個工廠方法模式裏的方法置爲靜態的,不須要建立實例,直接調用便可。
[java] view plaincopy
1. public class SendFactory {
2.
3. public static Sender produceMail(){
4. return new MailSender();
5. }
6.
7. public static Sender produceSms(){
8. return new SmsSender();
9. }
10. }
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. Sender sender = SendFactory.produceMail();
5. sender.Send();
6. }
7. }
輸出:this is mailsender!
整體來講,工廠模式適合:凡是出現了大量的產品須要建立,而且具備共同的接口時,能夠經過工廠方法模式進行建立。在以上的三種模式中,第一種若是傳 入的字符串有誤,不能正確建立對象,第三種相對於第二種,不須要實例化工廠類,因此,大多數狀況下,咱們會選用第三種——靜態工廠方法模式。
能夠看出工廠方法的加入,使得對象的數量成倍增加。當產品種類很是多時,會出現大量的與之對應的工廠對象,這不是咱們所但願的。由於若是不能避免這種情 況,能夠考慮使用簡單工廠模式與工廠方法模式相結合的方式來減小工廠類:即對於產品樹上相似的種類(通常是樹的葉子中互爲兄弟的)使用簡單工廠模式來實 現。
c、簡單工廠和工廠方法模式的比較
工廠方法模式和簡單工廠模式在定義上的不一樣是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式, 把核心放在一個實類上。工廠方法模式能夠容許不少實的工廠類從抽象工廠類繼承下來, 從而能夠在實際上成爲多個簡單工廠模式的綜合,從而推廣了簡單工廠模式。
反過來說,簡單工廠模式是由工廠方法模式退化而來。設想若是咱們很是肯定一個系統只須要一個實的工廠類, 那麼就不妨把抽象工廠類合併到實的工廠類中去。而這樣一來,咱們就退化到簡單工廠模式了。
d、抽象工廠模式
代碼:
//抽象工廠類
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
//具體工廠類,其中Food,Vehicle,Weapon是抽象類,
public class DefaultFactory extends AbstractFactory{
@Override
public Food createFood() {
return new Apple();
}
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
}
//測試類
public class Test {
public static void main(String[] args) {
AbstractFactory f = new DefaultFactory();
Vehicle v = f.createVehicle();
v.run();
Weapon w = f.createWeapon();
w.shoot();
Food a = f.createFood();
a.printName();
}
}
在抽象工廠模式中,抽象產品 (AbstractProduct) 多是一個或多個,從而構成一個或多個產品族(Product Family)。 在只有一個產品族的狀況下,抽象工廠模式實際上退化到工廠方法模式。
6、總結。
(1)簡單工廠模式是由一個具體的類去建立其餘類的實例,父類是相同的,父類是具體的。
(2)工廠方法模式是有一個抽象的父類定義公共接口,子類負責生成具體的對象,這樣作的目的是將類的實例化操做延遲到子類中完成。
(3)抽象工廠模式提供一個建立一系列相關或相互依賴對象的接口,而無須指定他們具體的類。它針對的是有多個產品的等級結構。而工廠方法模式針對的是一個產品的等級結構。
單例對象(Singleton)是一種經常使用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。這樣的模式有幾個好處:
1、某些類建立比較頻繁,對於一些大型的對象,這是一筆很大的系統開銷。
2、省去了new操做符,下降了系統內存的使用頻率,減輕GC壓力。
3、有些類如交易所的核心交易引擎,控制着交易流程,若是該類能夠建立多個的話,系統徹底亂了。(好比一個軍隊出現了多個司令員同時指揮,確定會亂成一團),因此只有使用單例模式,才能保證核心交易服務器獨立控制整個流程。
首先咱們寫一個簡單的單例類:
[java] view plaincopy
1. public class Singleton {
2.
3. /* 持有私有靜態實例,防止被引用,此處賦值爲null,目的是實現延遲加載 */
4. private static Singleton instance = null;
5.
6. /* 私有構造方法,防止被實例化 */
7. private Singleton() {
8. }
9.
10. /* 靜態工程方法,建立實例 */
11. public static Singleton getInstance() {
12. if (instance == null) {
13. instance = new Singleton();
14. }
15. return instance;
16. }
17.
18. /* 若是該對象被用於序列化,能夠保證對象在序列化先後保持一致 */
19. public Object readResolve() {
20. return instance;
21. }
22. }
這個類能夠知足基本要求,可是,像這樣毫無線程安全保護的類,若是咱們把它放入多線程的環境下,確定就會出現問題了,如何解決?咱們首先會想到對getInstance方法加synchronized關鍵字,以下:
[java] view plaincopy
1. public static synchronized Singleton getInstance() {
2. if (instance == null) {
3. instance = new Singleton();
4. }
5. return instance;
6. }
可是,synchronized關鍵字鎖住的是這個對象,這樣的用法,在性能上會有所降低,由於每次調用getInstance(),都要對對象上鎖,事實上,只有在第一次建立對象的時候須要加鎖,以後就不須要了,因此,這個地方須要改進。咱們改爲下面這個:
[java] view plaincopy
1. public static Singleton getInstance() {
2. if (instance == null) {
3. synchronized (instance) {
4. if (instance == null) {
5. instance = new Singleton();
6. }
7. }
8. }
9. return instance;
10. }
1、最簡單的實現
首先,能想到的最簡單的實現是,把類的構造函數寫成private的,從而保證別的類不能實例化此類。而後在類中返回一個靜態示例並返回給調用者。這樣,調用者就能夠經過這個引用使用這個實例了。
public class Singleton{ private static final Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } private Singleton(){ }}
如上例,外部使用者若是須要使用SingletonClass的實例,只能經過getInstance()方法,而且它的構造方法是private的,這樣就保證了只能有一個對象存在。
2、性能優化--lazy loaded
上面的代碼雖然簡單,可是有一個問題----不管這個類是否被使用,都會建立一個instance對象。若是這個建立很耗時,好比說連接10000次數據庫(誇張一點啦....),而且這個類還不必定會被使用,那麼這個建立過程就是無用的,怎麼辦呢?
爲了解決這個問題,咱們想到的新的解決方案:
public class SingletonClass { private static SingletonClass instance = null; public static SingletonClass getInstance() { if(instance == null) { instance = new SingletonClass(); } return instance; } private SingletonClass() { } }
代碼的變化有倆處----首先,把 instance 設置爲 null ,知道第一次使用的時候判是否爲 null 來建立對象。由於建立對象不在聲明處,因此那個 final 的修飾必須去掉。
咱們來想象一下這個過程。要使用 SingletonClass ,調用 getInstance()方法,第一次的時候發現instance時null,而後就建立一個對象,返回出去;第二次再使用的時候,由於這個 instance事static的,共享一個對象變量的,因此instance的值已經不是null了,所以不會再建立對象,直接將其返回。
這個過程就稱爲lazy loaded ,也就是遲加載-----直到使用的時候才經行加載。
這樣寫法也比較完美:可是還能夠優化
public class SingletonClass{ private static SingletonClass instance = null; public static SingletonClass getInstance(){ if(instance == null){ synchronized(SingletonClass.class){ if(instance == null){ instance = new SingletonClass(); } } } return instance; } private SingletonClass(){ } }
經過單例模式的學習告訴咱們:
1、單例模式理解起來簡單,可是具體實現起來仍是有必定的難度。
2、synchronized關鍵字鎖定的是對象,在用的時候,必定要在恰當的地方使用(注意須要使用鎖的對象和過程,可能有的時候並非整個對象及整個過程都須要鎖)。
到這兒,單例模式基本已經講完了,結尾處,筆者忽然想到另外一個問題,就是採用類的靜態方法,實現單例模式的效果,也是可行的,此處兩者有什麼不一樣?
首先,靜態類不能實現接口。(從類的角度說是能夠的,可是那樣就破壞了靜態了。由於接口中不容許有static修飾的方法,因此即便實現了也是非靜態的)
其次,單例能夠被延遲初始化,靜態類通常在第一次加載是初始化。之因此延遲加載,是由於有些類比較龐大,因此延遲加載有助於提高性能。
再次,單例類能夠被繼承,他的方法能夠被覆寫。可是靜態類內部方法都是static,沒法被覆寫。
最後一點,單例類比較靈活,畢竟從實現上只是一個普通的Java類,只要知足單例的基本需求,你能夠在裏面爲所欲爲的實現一些其它功能,可是靜態類 不行。從上面這些歸納中,基本能夠看出兩者的區別,可是,從另外一方面講,咱們上面最後實現的那個單例模式,內部就是用一個靜態類來實現的,因此,兩者有很 大的關聯,只是咱們考慮問題的層面不一樣罷了。兩種思想的結合,才能造就出完美的解決方案,就像HashMap採用數組+鏈表來實現同樣,其實生活中不少事 情都是這樣,單用不一樣的方法來處理問題,老是有優勢也有缺點,最完美的方法是,結合各個方法的優勢,才能最好的解決問題!
工廠類模式提供的是建立單個類的模式,而建造者模式則是將各類產品集中起來進行管理,用來建立複合對象,所謂複合對象就是指某個類具備不一樣的屬性,其實建造者模式就是前面抽象工廠模式和最後的Test結合起來獲得的。咱們看一下代碼:
還和前面同樣,一個Sender接口,兩個實現類MailSender和SmsSender。最後,建造者類以下:
[java] view plaincopy
1. public class Builder {
2.
3. private List<Sender> list = new ArrayList<Sender>();
4.
5. public void produceMailSender(int count){
6. for(int i=0; i<count; i++){
7. list.add(new MailSender());
8. }
9. }
10.
11. public void produceSmsSender(int count){
12. for(int i=0; i<count; i++){
13. list.add(new SmsSender());
14. }
15. }
16. }
測試類:
[java] view plaincopy
1. public class Test {
2.
3. public static void main(String[] args) {
4. Builder builder = new Builder();
5. builder.produceMailSender(10);
6. }
7. }
從這點看出,建造者模式將不少功能集成到一個類裏,這個類能夠創造出比較複雜的東西。因此與工程模式的區別就是:工廠模式關注的是建立單個產品,而建造者模式則關注建立符合對象,多個部分。所以,是選擇工廠模式仍是建造者模式,依實際狀況而定。
原型模式雖然是建立型的模式,可是與工程模式沒有關係,從名字便可看出,該模式的思想就是將一個對象做爲原型,對其進行復制、克隆,產生一個和原對象相似的新對象。本小結會經過對象的複製,進行講解。在Java中,複製對象是經過clone()實現的,先建立一個原型類:
[java] view plaincopy
1. public class Prototype implements Cloneable {
2.
3. public Object clone() throws CloneNotSupportedException {
4. Prototype proto = (Prototype) super.clone();
5. return proto;
6. }
7. }
很簡單,一個原型類,只須要實現Cloneable接口,覆寫clone方法,此處clone方法能夠改爲任意的名稱,由於Cloneable接口 是個空接口,你能夠任意定義實現類的方法名,如cloneA或者cloneB,由於此處的重點是super.clone()這句 話,super.clone()調用的是Object的clone()方法,而在Object類中,clone()是native的,具體怎麼實現,我會 在另外一篇文章中,關於解讀Java中本地方法的調用,此處再也不深究。在這兒,我將結合對象的淺複製和深複製來講一下,首先須要瞭解對象深、淺複製的概念:
淺複製:將一個對象複製後,基本數據類型的變量都會從新建立,而引用類型,指向的仍是原對象所指向的。
深複製:將一個對象複製後,不管是基本數據類型還有引用類型,都是從新建立的。簡單來講,就是深複製進行了徹底完全的複製,而淺複製不完全。
此處,寫一個深淺複製的例子:
[java] view plaincopy
1. public class Prototype implements Cloneable, Serializable {
2.
3. private static final long serialVersionUID = 1L;
4. private String string;
5.
6. private SerializableObject obj;
7.
8. /* 淺複製 */
9. public Object clone() throws CloneNotSupportedException {
10. Prototype proto = (Prototype) super.clone();
11. return proto;
12. }
13.
14. /* 深複製 */
15. public Object deepClone() throws IOException, ClassNotFoundException {
16.
17. /* 寫入當前對象的二進制流 */
18. ByteArrayOutputStream bos = new ByteArrayOutputStream();
19. ObjectOutputStream oos = new ObjectOutputStream(bos);
20. oos.writeObject(this);
21.
22. /* 讀出二進制流產生的新對象 */
23. ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
24. ObjectInputStream ois = new ObjectInputStream(bis);
25. return ois.readObject();
26. }
27.
28. public String getString() {
29. return string;
30. }
31.
32. public void setString(String string) {
33. this.string = string;
34. }
35.
36. public SerializableObject getObj() {
37. return obj;
38. }
39.
40. public void setObj(SerializableObject obj) {
41. this.obj = obj;
42. }
43.
44. }
45.
46. class SerializableObject implements Serializable {
47. private static final long serialVersionUID = 1L;
48. }
要實現深複製,須要採用流的形式讀入當前對象的二進制輸入,再寫出二進制數據對應的對象。
咱們接着討論設計模式,上篇文章我講完了5種建立型模式,這章開始,我將講下7種結構型模式:適配器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。其中對象的適配器模式是各類模式的起源,咱們看下面的圖:
適配器模式將某個類的接口轉換成客戶端指望的另外一個接口表示,目的是消除因爲接口不匹配所形成的類的兼容性問題。主要分爲三類:類的適配器模式、對象的適配器模式、接口的適配器模式。首先,咱們來看看類的適配器模式,先看類圖:
核心思想就是:有一個Source類,擁有一個方法,待適配,目標接口時Targetable,經過Adapter類,將Source的功能擴展到Targetable裏,看代碼:
[java] view plaincopy
1. public class Source {
2.
3. public void method1() {
4. System.out.println("this is original method!");
5. }
6. }
[java] view plaincopy
1. public interface Targetable {
2.
3. /* 與原類中的方法相同 */
4. public void method1();
5.
6. /* 新類的方法 */
7. public void method2();
8. }
[java] view plaincopy
1. public class Adapter extends Source implements Targetable {
2.
3. @Override
4. public void method2() {
5. System.out.println("this is the targetable method!");
6. }
7. }
Adapter類繼承Source類,實現Targetable接口,下面是測試類:
[java] view plaincopy
1. public class AdapterTest {
2.
3. public static void main(String[] args) {
4. Targetable target = new Adapter();
5. target.method1();
6. target.method2();
7. }
8. }
輸出:
this is original method!
this is the targetable method!
這樣Targetable接口的實現類就具備了Source類的功能
將以前介紹的全部排序算法整理成NumberSort類,代碼
NumberSort
Java語言引入了Java虛擬機,具備跨平臺運行的功能,可以很好地適應各類Web應用。同時,爲了提升Java語言的性能和健壯性,還引入瞭如垃圾回收機制等新功能,經過這些改進讓Java具備其獨特的工做原理。
1.Java虛擬機
Java源程序經過編譯器編譯成.Class文件,而後java虛擬機中的java 解釋器負責將字節碼文件解釋成爲特定的機器碼進行運行。
java是一種半編譯半解釋型語言。半編譯是指:java源代碼,會通過javac命令變成 .class文件。半解釋是指: .class文件被jvm解釋的過程。也就是由於jvm的半解釋纔有了java的動態語言特性:反射和annotation。
和android區別
alvik有本身的libdex庫負責對.class進行處理。libdex主要對.class進行處理生成本身的dex文件。主要作的工做是,對虛擬機指令進行轉換(dalvik是基於寄存器的,sun虛擬機是基於棧的),對類的靜態數據進行歸類、壓縮。
dalvik基於寄存器,而JVM基於stack ,Dalvik執行的是特有的DEX文件格式,而JVM運行的是*.class文件格式。
優點:1、在編譯時提早優化代碼而不是等到運行時
2、 虛擬機很小,使用的空間也小;被設計來知足可高效運行多種虛擬機實例。
Java虛擬機的創建須要針對不一樣的軟硬件平臺來實現,既要考慮處理器的型號,也要考慮操做系統的種類。由此在SPARC結構、X86結構、MIPS和PPC等嵌入式處理芯片上,在UNIX、Linux、Windows和部分實時操做系統上均可實現Java虛擬機。
2.無用內存自動回收機制
而在Java運行環境中,始終存在着一個系統級的線程,專門跟蹤內存的使用狀況, 按期檢測出再也不使用的內存,並自動進行回收,避免了內存的泄露,也減輕了程序員的工做量。
1.JVM
JVM是Java平臺的核心,爲了讓編譯產生的字節碼能更好地解釋與執行,所以把JVM分紅了6個部分:JVM解釋器、指令系統、寄存器、棧、存儲區和碎片回收區。
能夠很明顯看出,Android系統架構由5部分組成,分別是:Linux Kernel、Android Runtime、Libraries、Application Framework、Applications。第二部分將詳細介紹這5個部分。
如今咱們拿起手術刀來剖析各個部分。其實這部分SDK文檔已經幫咱們作得很好了,咱們要作的就是拿來主義,而後再加上本身理解。下面自底向上分析各層。
Android基於Linux 2.6提供核心系統服務,例如:安全、內存管理、進程管理、網絡堆棧、驅動模型。Linux Kernel也做爲硬件和軟件之間的抽象層,它隱藏具體硬件細節而爲上層提供統一的服務。
Android 包含一個核心庫的集合,提供大部分在Java編程語言核心類庫中可用的功能。每個Android應用程序是Dalvik虛擬機中的實例,運行在他們本身 的進程中。Dalvik虛擬機設計成,在一個設備能夠高效地運行多個虛擬機。Dalvik虛擬機可執行文件格式是.dex,dex格式是專爲Dalvik 設計的一種壓縮格式,適合內存和處理器速度有限的系統。
大多數虛擬機包括JVM都是基於棧的,而Dalvik虛擬機則是基於寄存器的。 兩種架構各有優劣,通常而言,基於棧的機器須要更多指令,而基於寄存器的機器指令更大。dx 是一套工具,能夠將 Java .class 轉換成 .dex 格式。一個dex文件一般會有多個.class。因爲dex有時必須進行最佳化,會使文件大小增長1-4倍,以ODEX結尾。
Dalvik虛擬機依賴於Linux 內核提供基本功能,如線程和底層內存管理。
Android包含一個C/C++庫的集合,供Android系統的各個組件使用。這些功能經過Android的應用程序框架(application framework)暴露給開發者。下面列出一些核心庫:
· 系統C庫——標準C系統庫(libc)的BSD衍生,調整爲基於嵌入式Linux設備
· 媒體庫——基於PacketVideo的OpenCORE。這些庫支持播放和錄製許多流行的音頻和視頻格式,以及靜態圖像文件,包括MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG
· 界面管理——管理訪問顯示子系統和無縫組合多個應用程序的二維和三維圖形層
· LibWebCore——新式的Web瀏覽器引擎,驅動Android 瀏覽器和內嵌的web視圖
· SGL——基本的2D圖形引擎
· 3D庫——基於OpenGL ES 1.0 APIs的實現。庫使用硬件3D加速或包含高度優化的3D軟件光柵
· FreeType ——位圖和矢量字體渲染
· SQLite ——全部應用程序均可以使用的強大而輕量級的關係數據庫引擎
經過提供開放的開發平臺,Android使開發者可以編制極其豐富和新穎的應用程序。開發者能夠自由地利用設備硬件優點、訪問位置信息、運行後臺服務、設置鬧鐘、向狀態欄添加通知等等,不少不少。
開發者能夠徹底使用核心應用程序所使用的框架APIs。應用程序的體系結構旨在簡化組件的重用,任何應用程序都能發佈他的功能且任何其餘應用程序能夠使用這些功能(須要服從框架執行的安全限制)。這一機制容許用戶替換組件。
全部的應用程序實際上是一組服務和系統,包括:
· 視圖(View)——豐富的、可擴展的視圖集合,可用於構建一個應用程序。包括包括列表、網格、文本框、按鈕,甚至是內嵌的網頁瀏覽器
· 內容提供者(Content Providers)——使應用程序能訪問其餘應用程序(如通信錄)的數據,或共享本身的數據
· 資源管理器(Resource Manager)——提供訪問非代碼資源,如本地化字符串、圖形和佈局文件
· 通知管理器(Notification Manager)——使全部的應用程序可以在狀態欄顯示自定義警告
· 活動管理器(Activity Manager)——管理應用程序生命週期,提供通用的導航回退功能
Android裝配一個核心應用程序集合,包括電子郵件客戶端、SMS程序、日曆、地圖、瀏覽器、聯繫人和其餘設置。全部應用程序都是用Java編程語言寫的。更加豐富的應用程序有待咱們去開發!
1、Socket通訊簡介
Android 與服務器的通訊方式主要有兩種,一是Http通訊,一是Socket通訊。二者的最大差別在於,http鏈接使用的是「請求—響應方式」,即在請求時創建 鏈接通道,當客戶端向服務器發送請求後,服務器端才能向客戶端返回數據。而Socket通訊則是在雙方創建起鏈接後就能夠直接進行數據的傳輸,在鏈接時可 實現信息的主動推送,而不須要每次由客戶端想服務器發送請求。 那麼,什麼是socket?Socket又稱套接字,在程序內部提供了與外界通訊的端口,即端口通訊。經過創建socket鏈接,可爲通訊雙方的數據傳輸 傳提供通道。socket的主要特色有數據丟失率低,使用簡單且易於移植。
1.2Socket的分類
根據不一樣的的底層協議,Socket的實現是多樣化的。本指南中只介紹TCP/IP協議族的內容,在這個協議族當中主要的Socket類型爲流套接字 (streamsocket)和數據報套接字(datagramsocket)。流套接字將TCP做爲其端對端協議,提供了一個可信賴的字節流服務。數據 報套接字使用UDP協議,提供數據打包發送服務。
2、Socket 基本通訊模型
3、Socket基本實現原理
3.1基於TCP協議的Socket
服務器端首先聲明一個ServerSocket對象而且指定端口號,而後調 用Serversocket的accept()方法接收客戶端的數據。accept()方法在沒有數據進行接收的處於堵塞狀態。 (Socketsocket=serversocket.accept()),一旦接收到數據,經過inputstream讀取接收的數據。
客戶端建立一個Socket對象,指定服務器端的ip地址和端口號 (Socketsocket=newSocket("172.168.10.108",8080);),經過inputstream讀取數據,獲取服務器 發出的數據(OutputStreamoutputstream=socket.getOutputStream()),最後將要發送的數據寫入到 outputstream便可進行TCP協議的socket數據傳輸。
3.2基於UDP協議的數據傳輸
服務器端首先建立一個DatagramSocket對象,而且指點監聽的端 口。接下來建立一個空的DatagramSocket對象用於接收數據 (bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data,data.length)), 使用DatagramSocket的receive方法接收客戶端發送的數據,receive()與serversocket的accepet()相似, 在沒有數據進行接收的處於堵塞狀態。
客戶端也建立個DatagramSocket對象,而且指點監聽的端口。接 下來建立一個InetAddress對象,這個對象相似與一個網絡的發送地址 (InetAddressserveraddress=InetAddress.getByName("172.168.1.120")).定義要發送的 一個字符串,建立一個DatagramPacket對象,並制定要講這個數據報包發送到網絡的那個地址以及端口號,最後使用DatagramSocket 的對象的send()發送數據。*(Stringstr="hello";bytedata[]=str.getByte(); DatagramPacketpacket=new DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet);)
4、android 實現socket簡單通訊
4.1使用TCP協議通訊
android端實現:
[java] view plaincopy
1. protected void connectServerWithTCPSocket() {
2.
3. Socket socket;
4. try {// 建立一個Socket對象,並指定服務端的IP及端口號
5. socket = new Socket("192.168.1.32", 1989);
6. // 建立一個InputStream用戶讀取要發送的文件。
7. InputStream inputStream = new FileInputStream("e://a.txt");
8. // 獲取Socket的OutputStream對象用於發送數據。
9. OutputStream outputStream = socket.getOutputStream();
10. // 建立一個byte類型的buffer字節數組,用於存放讀取的本地文件
11. byte buffer[] = new byte[4 * 1024];
12. int temp = 0;
13. // 循環讀取文件
14. while ((temp = inputStream.read(buffer)) != -1) {
15. // 把數據寫入到OuputStream對象中
16. outputStream.write(buffer, 0, temp);
17. }
18. // 發送讀取的數據到服務端
19. outputStream.flush();
20.
21. /** 或建立一個報文,使用BufferedWriter寫入,看你的需求 **/
22. // String socketData = "[2143213;21343fjks;213]";
23. // BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
24. // socket.getOutputStream()));
25. // writer.write(socketData.replace("\n", " ") + "\n");
26. // writer.flush();
27. /************************************************/
28. } catch (UnknownHostException e) {
29. e.printStackTrace();
30. } catch (IOException e) {
31. e.printStackTrace();
32. }
33.
34. }
服務器端簡單實現:
[java] view plaincopy
1. public void ServerReceviedByTcp() {
2. // 聲明一個ServerSocket對象
3. ServerSocket serverSocket = null;
4. try {
5. // 建立一個ServerSocket對象,並讓這個Socket在1989端口監聽
6. serverSocket = new ServerSocket(1989);
7. // 調用ServerSocket的accept()方法,接受客戶端所發送的請求,
8. // 若是客戶端沒有發送數據,那麼該線程就停滯不繼續
9. Socket socket = serverSocket.accept();
10. // 從Socket當中獲得InputStream對象
11. InputStream inputStream = socket.getInputStream();
12. byte buffer[] = new byte[1024 * 4];
13. int temp = 0;
14. // 從InputStream當中讀取客戶端所發送的數據
15. while ((temp = inputStream.read(buffer)) != -1) {
16. System.out.println(new String(buffer, 0, temp));
17. }
18. serverSocket.close();
19. } catch (IOException e) {
20. e.printStackTrace();
21. }
22. }
4.2使用UDP協議通訊
客戶端發送數據實現:
[java] view plaincopy
1. protected void connectServerWithUDPSocket() {
2.
3. DatagramSocket socket;
4. try {
5. //建立DatagramSocket對象並指定一個端口號,注意,若是客戶端須要接收服務器的返回數據,
6. //還須要使用這個端口號來receive,因此必定要記住
7. socket = new DatagramSocket(1985);
8. //使用InetAddress(Inet4Address).getByName把IP地址轉換爲網絡地址
9. InetAddress serverAddress = InetAddress.getByName("192.168.1.32");
10. //Inet4Address serverAddress = (Inet4Address) Inet4Address.getByName("192.168.1.32");
11. String str = "[2143213;21343fjks;213]";//設置要發送的報文
12. byte data[] = str.getBytes();//把字符串str字符串轉換爲字節數組
13. //建立一個DatagramPacket對象,用於發送數據。
14. //參數一:要發送的數據 參數二:數據的長度 參數三:服務端的網絡地址 參數四:服務器端端口號
15. DatagramPacket packet = new DatagramPacket(data, data.length ,serverAddress ,10025);
16. socket.send(packet);//把數據發送到服務端。
17. } catch (SocketException e) {
18. e.printStackTrace();
19. } catch (UnknownHostException e) {
20. e.printStackTrace();
21. } catch (IOException e) {
22. e.printStackTrace();
23. }
24. }
客戶端接收服務器返回的數據:
[java] view plaincopy
1. public void ReceiveServerSocketData() {
2. DatagramSocket socket;
3. try {
4. //實例化的端口號要和發送時的socket一致,不然收不到data
5. socket = new DatagramSocket(1985);
6. byte data[] = new byte[4 * 1024];
7. //參數一:要接受的data 參數二:data的長度
8. DatagramPacket packet = new DatagramPacket(data, data.length);
9. socket.receive(packet);
10. //把接收到的data轉換爲String字符串
11. String result = new String(packet.getData(), packet.getOffset(),
12. packet.getLength());
13. socket.close();//不使用了記得要關閉
14. System.out.println("the number of reveived Socket is :" + flag
15. + "udpData:" + result);
16. } catch (SocketException e) {
17. e.printStackTrace();
18. } catch (IOException e) {
19. e.printStackTrace();
20. }
21. }
服務器接收客戶端實現:
[java] view plaincopy
1. public void ServerReceviedByUdp(){
2. //建立一個DatagramSocket對象,並指定監聽端口。(UDP使用DatagramSocket)
3. DatagramSocket socket;
4. try {
5. socket = new DatagramSocket(10025);
6. //建立一個byte類型的數組,用於存放接收到得數據
7. byte data[] = new byte[4*1024];
8. //建立一個DatagramPacket對象,並指定DatagramPacket對象的大小
9. DatagramPacket packet = new DatagramPacket(data,data.length);
10. //讀取接收到得數據
11. socket.receive(packet);
12. //把客戶端發送的數據轉換爲字符串。
13. //使用三個參數的String方法。參數一:數據包 參數二:起始位置 參數三:數據包長
14. String result = new String(packet.getData(),packet.getOffset() ,packet.getLength());
15. } catch (SocketException e) {
16. e.printStackTrace();
17. } catch (IOException e) {
18. e.printStackTrace();
19. }
20. }
5、總結:
使用UDP方式android端和服務器端接收能夠看出,其實android端和服務器端的發送和接收大庭相徑,只要端口號正確了,相互通訊就沒有問題,TCP使用的是流的方式發送,UDP是以包的形式發送。
本示例以Servlet爲例,演示Android與Servlet的通訊。
衆所周知,Android與服務器通訊一般採用HTTP通訊方式和Socket通訊方式,而HTTP通訊方式又分get和post兩種方式。至於Socket通訊會在之後的博文中介紹。
HTTP協議簡介:
HTTP (Hypertext Transfer Protocol ),是Web聯網的基礎,也是手機聯網經常使用的協議之一,HTTP協議是創建在TCP協議之上的一種協議。
HTTP鏈接最顯 著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。 在HTTP 1.0中,客戶端的每次請求都要求創建一次單獨的鏈接,在處理完本次請求後,就自動釋放鏈接。 在HTTP 1.1中則能夠在一次鏈接中處理多個請求,而且多個請求能夠重疊進行,不須要等待一個請求結束後再發送下一個請求。
由 於HTTP在每次請求結束後都會主動釋放鏈接,所以HTTP鏈接是一種「短鏈接」、「無狀態」,要保持客戶端程序的在線狀態,須要不斷地向服務器發起鏈接 請求。一般的作法是即便不須要得到任何數據,客戶端也保持每隔一段固定的時間向服務器發送一次「保持鏈接」的請求,服務器在收到該請求後對客戶端進行回 復,代表知道客戶端「在線」。若服務器長時間沒法收到客戶端的請求,則認爲客戶端「下線」,若客戶端長時間沒法收到服務器的回覆,則認爲網絡已經斷開。
基於HTTP1.0協議的客戶端在每次向服務器發出請求後,服務器就會向客戶端返回響應消息,在確認客戶端已經收到響應消息後,服務端就會關閉網絡鏈接。在這個數據傳輸過程當中,並不保存任何歷史信息和狀態信息,所以,HTTP協議也被認爲是無狀態的協議。
HTTP1.1 和HTTP1.0相比較而言,最大的區別就是增長了持久鏈接支持。當客戶端使用HTTP1.1協議鏈接到服務器後,服務器就將關閉客戶端鏈接的主動權交還 給客戶端;也就是說,只要不調用Socket類的close方法關閉網絡鏈接,就能夠繼續向服務器發送HTTP請求。
HTTP鏈接使用的是「請求—響應」的方式(2次握手),不只在請求時須要先創建鏈接,並且須要客戶端向服務器發出請求後,服務器端才能回覆數據。而Socket鏈接在雙方創建起鏈接後就能夠直接進行數據的傳輸
HTTP協議的特色:
支持B/S及C/S模式;
簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法經常使用的有GET、HEAD、POST。
靈活:HTTP 容許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type 加以標記;
無狀態:HTTP 協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺乏狀態意味着若是後續處理須要前面的信息,則它必須重傳,這樣可能致使每次鏈接傳送的數據量增大。
HTTP協議請求方法:
請求行中包括了請求方法,解釋以下:
GET 請求獲取Request-URI 所標識的資源;
POST 在Request-URI 所標識的資源後附加新的數據;
HEAD 請求獲取由Request-URI 所標識的資源的響應消息報頭
PUT 請求服務器存儲一個資源,並用Request-URI 做爲其標識
DELETE 請求服務器刪除Request-URI 所標識的資源;
TRACE 請求服務器回送收到的請求信息,主要用於測試或診斷
CONNECT 保留未來使用
OPTIONS 請求查詢服務器的性能,或者查詢與資源相關的選項和需求
Get與Post請求區別:
Post 請求能夠向服務器傳送數據,並且數據放在HTML HEADER內一塊兒傳送到服務端URL地址,數據對用戶不可見。而get是把參數數據隊列加到提交的URL中,值和表單內各個字段一一對應, 例如(http://www.baidu.com/s?w=%C4&inputT=2710)
get 傳送的數據量較小,不能大於2KB。post傳送的數據量較大,通常被默認爲不受限制。但理論上,IIS4中最大量爲80KB,IIS5中爲100KB。
get安全性很是低,post安全性較高。
在Android開發中咱們常常會用到網絡鏈接功能與服務器進行數據的交互,爲此Android的SDK提供了Apache的HttpClient來方便咱們使用各類Http服務
///
Get() 先建立一個HttpClient 而後再建立一個HttpGet,經過HttpClient的execute方法來發送一個HttpGet而且返回String內容。
try {
// 建立一個默認的HttpClient
HttpClient httpclient =new DefaultHttpClient();
// 建立一個GET請求
HttpGet request =new HttpGet("www.google.com");
// 發送GET請求,並將響應內容轉換成字符串
String response = httpclient.execute(request, new BasicResponseHandler());
Log.v("response text", response);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
///////////////////////////////
Post()
publicstatic String post(String url, NameValuePair... params) {
try {
// 編碼參數
List<NameValuePair> formparams =new ArrayList<NameValuePair>(); // 請求參數
for (NameValuePair p : params) {
formparams.add(p);
}
UrlEncodedFormEntity entity =new UrlEncodedFormEntity(formparams,
CHARSET);
// 建立POST請求
HttpPost request =new HttpPost(url);
request.setEntity(entity);
// 發送請求
HttpClient client = getHttpClient();
HttpResponse response = client.execute(request);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
thrownew RuntimeException("請求失敗");
}
HttpEntity resEntity = response.getEntity();
return (resEntity ==null) ?null : EntityUtils.toString(resEntity, CHARSET);
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (ClientProtocolException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (IOException e) {
thrownew RuntimeException("鏈接失敗", e);
}
}
整理:楊光福&王飛龍
時間倉促,不免有不周之處,請見諒。
http://www.cnblogs.com/pepcod/archive/2013/02/11/2937403.html
能夠用咱們上課講的說
也能夠參照
http://blog.saymagic.cn/2015/01/30/android-pic-three-cache.html
http://www.cnblogs.com/elliotta/p/3633752.html
http://blog.csdn.net/yudajun/article/details/9323941
技術方面說明
http://blog.csdn.net/lwyygydx/article/details/41870377
功能改進方面說明
http://digi.tech.qq.com/a/20150121/012030.htm
能夠參照李延磊老師的
也能夠參照連接
http://blog.csdn.net/fancylovejava/article/details/39927539
xUtils,Gson 極光推送 都講過,忽略
友盟第三方登陸
http://blog.umeng.com/uncategorized/4160.html
第三方登陸案例
http://blog.csdn.net/yueqinglkong/article/details/15028041
http://blog.csdn.net/lyf_007217/article/details/8542238
http://www.cnblogs.com/devinzhang/p/3856200.html
http://www.360doc.com/content/14/0402/09/10504424_365635496.shtml
http://blog.csdn.net/androidzhaoxiaogang/article/details/7910364
http://www.2cto.com/kf/201409/335964.html
http://blog.csdn.net/u200814499/article/details/40391443
http://blog.csdn.net/jiangliloveyou/article/details/9849775
http://blog.csdn.net/lnb333666/article/details/7471292
http://skywen.iteye.com/blog/1811310
已經講了,請看視頻
已經講了,請看視頻
已經講了,請看視頻
http://blog.csdn.net/wuqiong_524itcast/article/details/25378685
http://blog.csdn.net/wangshione/article/details/8490245
http://blog.csdn.net/lnb333666/article/details/8031770
1.垃圾收集算法的核心思想
Java語言創建了垃圾收集機制,用以跟蹤正在使用的對象和發現並回收再也不使用(引用)的對象。該機制能夠有效防範動態內存分配中因內存垃圾過多而引起的內存耗盡,以及不恰當的內存釋放所形成的內存非法引用。
垃圾收集算法的核心思想是:對虛擬機可用內存空間,即堆空間中的對象進行識別,若是對象正在被引用,那麼稱其爲存活對象,反之,若是對象再也不被引用,則 爲垃圾對象,能夠回收其佔據的空間,用於再分配。垃圾收集算法的選擇和垃圾收集系統參數的合理調節直接影響着系統性能,所以須要開發人員作比較深刻的瞭解。
2.觸發主GC(Garbage Collector)的條件
JVM進行次GC的頻率很高,但由於這種GC佔用時間極短,因此對系統產生的影響不大。更值得關注的是主GC的觸發條件,由於它對系統影響很明顯。總的來講,有兩個條件會觸發主GC:
①當應用程序空閒時,即沒有應用線程在運行時,GC會被調用。由於GC在優先級最低的線程中進行,因此當應用忙時,GC線程就不會被調用,但如下條件除外。
②Java堆內存不足時,GC會被調用。當應用線程在運行,並在運行過程當中建立新對象,若這時內存空間不足,JVM就會強制地調用GC線程,以 便回收內存用於新的分配。若GC一次以後仍不能知足內存分配的要求,JVM會再進行兩次GC做進一步的嘗試,若仍沒法知足要求,則 JVM將報「out of memory」的錯誤,Java應用將中止。
3.減小GC開銷的措施
根據上述GC的機制,程序的運行會直接影響系統環境的變化,從而影響GC的觸發。若不針對GC的特色進行設計和編碼,就會出現內存駐留等一系列負面影響。爲了不這些影響,基本的原則就是儘量地減小垃圾和減小GC過程當中的開銷。具體措施包括如下幾個方面:
(1)不要顯式調用System.gc()
此函數建議JVM進行主GC,雖然只是建議而非必定,但不少狀況下它會觸發主GC,從而增長主GC的頻率,也即增長了間歇性停頓的次數。
(2)儘可能減小臨時對象的使用
臨時對象在跳出函數調用後,會成爲垃圾,少用臨時變量就至關於減小了垃圾的產生,從而延長了出現上述第二個觸發條件出現的時間,減小了主GC的機會。
(3)對象不用時最好顯式置爲Null
通常而言,爲Null的對象都會被做爲垃圾處理,因此將不用的對象顯式地設爲Null,有利於GC收集器斷定垃圾,從而提升了GC的效率。
(4)儘可能使用StringBuffer,而不用String來累加字符串(詳見blog另外一篇文章JAVA中String與StringBuffer)
因爲String是固定長的字符串對象,累加String對象時,並不是在一個String對象中擴增,而是從新建立新的String對象,如 Str5=Str1+Str2+Str3+Str4,這條語句執行過程當中會產生多個垃圾對象,由於對次做「+」操做時都必須建立新的String對象,但 這些過渡對象對系統來講是沒有實際意義的,只會增長更多的垃圾。避免這種狀況能夠改用StringBuffer來累加字符串,因StringBuffer 是可變長的,它在原有基礎上進行擴增,不會產生中間對象。
(5)能用基本類型如Int,Long,就不用Integer,Long對象
基本類型變量佔用的內存資源比相應對象佔用的少得多,若是沒有必要,最好使用基本變量。
(6)儘可能少用靜態對象變量
靜態變量屬於全局變量,不會被GC回收,它們會一直佔用內存。
(7)分散對象建立或刪除的時間
集中在短期內大量建立新對象,特別是大對象,會致使忽然須要大量內存,JVM在面臨這種狀況時,只能進行主GC,以回收內存或整合內存碎片, 從而增長主GC的頻率。集中刪除對象,道理也是同樣的。它使得忽然出現了大量的垃圾對象,空閒空間必然減小,從而大大增長了下一次建立新對象時強制主GC 的機會。
gc()函數的做用只是提醒虛擬機:程序員但願進行一次垃圾回收。可是它不能保證垃圾回收必定會進行,並且具體何時進行是取決於具體的虛擬機的,不一樣的虛擬機有不一樣的對策。在Davilk中,給程序分配的內存是根據機型廠商的不一樣而不一樣(如今大部分爲32MB),在VM內部會將內存分爲:java使用的內存,Native使用的內存,他們之間不能共享,當某一方面不足
的時候必須向VM申請,而不能直接使用另一個的內存。
出現內存泄漏的可能性:
出現狀況:
1. 數據庫的cursor沒有關閉
2.構造adapter時,沒有使用緩存contentview
衍生listview的優化問題-----減小建立view的對象,充分使用contentview,能夠使用一靜態類來優化處理getview的過程
3.Bitmap對象不使用時採用recycle()釋放內存
4.activity中的對象的生命週期大於activity
調試方法: DDMS==> HEAPSZIE==>dataobject==>[Total Size]
1、 Android的內存機制
Android的程序由Java語言編寫,因此Android的內存管理與Java的內存管理類似。程序員經過new爲對象分配內存,全部對象在java 堆內分配空間;然而對象的釋放是由垃圾回收器來完成的。C/C++中的內存機制是「誰污染,誰治理」,java的就比較人性化了,給咱們請了一個專門的清 潔工(GC)
2、GC是什麼? 爲何要有GC?
GC是垃圾收集的意思(Gabage Collection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠 自動監測對象是否超過做用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操做方法。
4、垃圾回收器的基本原理是什麼?垃圾回收器能夠立刻回收內存嗎?有什麼辦法主動通知虛擬機進行垃圾回收?
對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對 象。經過這種方式肯定哪些對象是"可達的",哪些對象是"不可達的"。當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。能夠。程序員可 以手動執行System.gc(),通知GC運行,可是Java語言規範並不保證GC必定會執行。
間而忘記了釋放。若是程序中存在對無用對象的引用,那麼這些對象就會駐留內存,消耗內存,由於沒法讓垃圾回收器GC驗證這些對象是否再也不須要。若是存在對 象的引用,這個對象就被定義爲"有效的活動",同時不會被釋放。要肯定對象所佔內存將被回收,咱們就要務必確認該對象再也不會被使用。典型的作法就是把對象 數據成員設爲null或者從集合中移除該對象。但當局部變量不須要時,不需明顯的設爲null,由於一個方法執行完畢時,這些引用會自動被清理。
Java帶垃圾回收的機制,爲何還會內存泄露呢?舉例:
[java] view plaincopyprint?
1. Vector v = new Vector(10);
2. for (int i = 1; i < 100; i++) {
3. Object o = new Object();
4. v.add(o);
5. o = null;
6. }// 此時,全部的Object對象都沒有被釋放,由於變量v引用這些對象。
Java 內存泄露的根本緣由就是 保存了不可能再被訪問的變量類型的引用
6、Android的內存溢出
Android的內存溢出是如何發生的?
Android的虛擬機是基於寄存器的Dalvik,它的最大堆大小通常是16M,有的機器爲24M。也就是說咱們所能利用的內存空間是有限的。若是咱們的內存佔用超過了必定的水平就會出現OutOfMemory的錯誤。
爲何會出現內存不夠用的狀況呢?我想緣由主要有兩個:
因爲咱們程序的失誤,長期保持某些資源(如Context)的引用,形成內存泄露,資源形成得不到釋放。保存了多個耗用內存過大的對象(如Bitmap),形成內存超出限制。
(一)、(二)中,咱們瞭解了一些基本概念。
600dp的含義是:表明這個設備的最短的那一邊。
獲取設備的最短邊的代碼是:Configuration config = getResources().getConfiguration();
int smallestScreenWidth = config.smallestScreenWidthDp;
這個時候拿smallestScreenWidth 與600想比較就能夠知道該設備可否讀取裏面的資源了。
)
除此以外,爲了方便適配,在編碼時咱們還應該注意什麼呢,主要有如下幾點:
(1)多使用權重(android:layout_weight)
尤爲是在tab切換佈局,listview title及Item佈局等狀況下;
(2)設置寬度和高度時,儘可能使用match_parent和wrap_content,避免把控件寬高設死;
(3)父容器佈局選用
多使用RelativeLayout,FrameLayout,GridLayout等,減小布局層次。固然,在使用
權重時,得采用LinearLayout;
(4) 在xml裏,設置高度、寬度採用dp(dip),設置字體採用sp。
(應該注意,在代碼裏面,咱們寫的setHeight(...)單位是px)
(二)
那麼在具體開發中,咱們應該注意什麼呢。
首先,咱們必需要知道,其實適配的關鍵在於兩點:
(1)不一樣分辨率設備的適配,這點在單位的使用上用dp、sp以及圖片資源存放於不一樣的drawable文件夾就能夠解決問題;
(2)不一樣尺寸的適配,這點主要靠將相關值以及佈局文件放置於不一樣的文件夾中來解決。
2.1 values文件夾
能夠在工程下建立不一樣的values文件夾:values-sw480dp, values-sw600dp,
values-sw720dp-land等。好比一個控件的寬度,在10寸pad上是10dp,在8寸pad
上是5dp。這時,你能夠定義一個變量,button_width,而後在values-sw600dp
下寫5dp,在values-sw720-land下寫
10dp。這樣就達到了在不一樣尺寸pad上,
相應控件大小不同的效果。
2.1 layout文件夾
若是在不一樣尺寸設備上展現的佈局有明顯差異,僅僅用values不一樣已經難以控制,
那麼就能夠考慮寫不一樣的佈局文件置於不一樣的layout文件夾下,android會根據設備
尺寸去加載相應文件夾下的佈局文件。如:layout-sw480dp,layout-sw600dp,
layout-sw700dp等。
值得注意的是,若是不是頗有必要,儘可能採用2.1方案,方便維護。若是尺寸和分辨率都不一樣,
那麼就要結合(1)、(2)考慮了。
(補充:其實values文件夾和layout文件夾不只僅是根據尺寸判斷,也和分辨率有關,不過在一般狀況下,
綜合計算考慮,僅根據尺寸判斷就能夠了:
www.itlanbao.com 本網站裏面分享不少android特效,更多的面試資料在IT藍豹資訊部分 ,但願可以給你幫助,歡迎到IT藍豹上互相學習。
|
ArrayList |
Vector |
LinkedList |
實現原理 |
數組 |
數組 |
雙向鏈表 |
線程安全 |
否 |
是 |
否 |
優勢 |
1.數組實現優於遍歷 |
1.數組實現優於遍歷 |
1.節點的增刪無需對象的重建 |
缺點 |
1.非線程安全 |
1.數組中未使用的元素形成空間的浪費 |
1.遍歷效率較低 |
擴容 |
0.5倍增量 |
1倍增量 |
按需增刪 |
使用場景 |
1.無線程的要求。 |
1.有線程安全的要求 |
增刪場景較多的時候 |
11.int與Integer的區別
|
int |
Integer |
類型 |
基本類型 |
複合類型 |
默認值 |
0 |
null |
存儲 |
棧(局部變量) |
堆上(只能經過new建立) |
方法 |
基本類型無方法 |
有 |
速度 |
快(棧上 的操做相對快) |
慢 |
泛型支持 |
否(java中的泛型不支持,C++中的模板支持) |
支持 |
容器類支持 |
否(直接使用一般會進行裝箱操做) |
支持 |
存在乎義 |
1.歷史緣由(順延C/C++中存在) |
基本類型int的包裝類 |
Checked Exception:在編譯時就可以被Java編譯器所檢測到的。
UncheckedException:則是編譯時,java編譯器不能檢查到。
|
RuntimeException |
普通Exception |
Error |
受控異常 |
否 |
是 |
否 |
產生緣由 |
開發者的編程錯誤 |
因爲外界環境所限, |
Java運行時的系統錯誤,資源耗盡,是一種嚴重的, |
例子 |
NullPointerException |
ClassNotFoundException |
VirtualMachineError |
final:關鍵字,表不變
修飾:
· 方法:方法不可Override
· 類:不可被繼承
· 基本類型量:常量,值不可變
· 符合類型量:引用不可變,即引用的值不可變
[java] view plaincopy
1. final Object o1 = new Object();
2. o1 = new Object();
finally:關鍵字,Java異常處理機制的一部分,在異常發生時,用來提供一個必要的清理的機會。
finalize:Object類的方法(參考自百度百科)
意義:Java技術容許使用finalize()方法在垃圾回收器將對象回收以前,作一些必要的清理操做。
調用前提:這個對象肯定沒有被引用到。
工做原理:
· 垃圾收集器準備好釋放對象佔用的空間。
· 首先調用其finalize方法。
· 下一次垃圾收集過程當中,真正回收內存。
不肯定性:
· finalize的執行時間是不缺定的。
· 一個對象引用另外一個對象,並不能保證finalize的方法按照特定的執行順序。
|
Override |
Overload |
簽名+返回值 |
相同 |
方法名相同,簽名不一樣 |
關係 |
父子類繼承關係 |
一般是同一類層次中 |
識別 |
運行時多態 |
編譯時多態 |
修飾符限制 |
非private |
無特別 |
異常關係 |
子類方法不能拋出被父類方法更多的異常 |
無特別 |
可見性關係 |
子類不能比父類訪問權限更窄 |
無特別 |
Collection:接口,集合類的接口,一個契約,提供了集合基本的大小,添加,清除,遍歷方法等。
Collections:工具類,提供了不少靜態方法,給集合提供一些查詢,比較,排序,交換,線程安全化等方法。
package com.jue.test;
public class TestMain {
public static void main(String[] args) {
Integer i1 = 1;
Integer i11 = 1;
System.out.println(i1 == i11);
Integer i2 = 200;
Integer i22 = 200;
System.out.println(i2 == i22);
}
}
結果 :True,false
分析:反編譯結果爲 Integer i1 = Integer.valueOf(1);
能夠看出,對於Integer i = 1;編譯器作了額外的處理,即Integer.valueof();能夠看出Integer對於必定 範圍內的數字從Cache中取得,對於額外的,調用new建立。
故能夠知道Integer的大小,默認是從-128到127,對於這個範圍內的數組作了緩存的處理。 對於額外的,調用new建立
|
wait |
sleep |
所屬類 |
Object |
Thread |
意義 |
讓線程掛起 |
讓線程休眠指定的時間 |
釋放鎖 |
是 |
否(這個跟鎖原本就沒有關係) |
恢復 |
1.有參:wait指定時間 |
1.根據參數長度自動恢復。 |
使用限制 |
wait,notify必須持有當前對象鎖的狀況下調用 |
無特別 |
拋出異常 |
否 |
是 |
靜態方法 |
否 |
是 |
HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在於HashMap容許空(null)鍵值(key),因爲非線程安全,效率上可能高於Hashtable。
HashMap容許將null做爲一個entry的key或者value,而Hashtable不容許。
HashMap把Hashtable的contains方法去掉了,改爲containsvalue和containsKey。由於contains方法容易讓人引發誤解。
整體來講設計模式分爲三大類:
建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行爲型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
其實還有兩類:併發型模式和線程池模式。用一個圖片來總體描述一下:
http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
首先,建立兩者的共同接口:
[java] view plaincopy
1. public interface Sender {
2. public void Send();
3. }
其次,建立實現類:
[java] view plaincopy
1. public class MailSender implements Sender {
2. @Override
3. public void Send() {
4. System.out.println("this is mailsender!");
5. }
6. }
[java] view plaincopy
1. public class SmsSender implements Sender {
2.
3. @Override
4. public void Send() {
5. System.out.println("this is sms sender!");
6. }
7. }
最後,建工廠類:
[java] view plaincopy
1. public class SendFactory {
2.
3. public Sender produce(String type) {
4. if ("mail".equals(type)) {
5. return new MailSender();
6. } else if ("sms".equals(type)) {
7. return new SmsSender();
8. } else {
9. System.out.println("請輸入正確的類型!");
10. return null;
11. }
12. }
13. }
咱們來測試下:
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produce("sms");
6. sender.Send();
7. }
8. }
輸出:this is sms sender!
a、多個工廠方法模式,是對普通工廠方法模式的改進,在普通工廠方法模式中,若是傳遞的字符串出錯,則不能正確建立對象,而多個工廠方法模式是提供多個工廠方法,分別建立對象。關係圖:
將上面的代碼作下修改,改動下SendFactory類就行,以下:
[java] view plaincopypublic class SendFactory {
public Sender produceMail(){
1. return new MailSender();
2. }
3.
4. public Sender produceSms(){
5. return new SmsSender();
6. }
7. }
測試類以下:
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produceMail();
6. sender.Send();
7. }
8. }
輸出:this is mailsender!
b、靜態工廠方法模式,將上面的多個工廠方法模式裏的方法置爲靜態的,不須要建立實例,直接調用便可。
[java] view plaincopy
1. public class SendFactory {
2.
3. public static Sender produceMail(){
4. return new MailSender();
5. }
6.
7. public static Sender produceSms(){
8. return new SmsSender();
9. }
10. }
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. Sender sender = SendFactory.produceMail();
5. sender.Send();
6. }
7. }
輸出:this is mailsender!
整體來講,工廠模式適合:凡是出現了大量的產品須要建立,而且具備共同的接口時,能夠經過工廠方法模式進行建立。在以上的三種模式中,第一種若是傳 入的字符串有誤,不能正確建立對象,第三種相對於第二種,不須要實例化工廠類,因此,大多數狀況下,咱們會選用第三種——靜態工廠方法模式。
能夠看出工廠方法的加入,使得對象的數量成倍增加。當產品種類很是多時,會出現大量的與之對應的工廠對象,這不是咱們所但願的。由於若是不能避免這種情 況,能夠考慮使用簡單工廠模式與工廠方法模式相結合的方式來減小工廠類:即對於產品樹上相似的種類(通常是樹的葉子中互爲兄弟的)使用簡單工廠模式來實 現。
c、簡單工廠和工廠方法模式的比較
工廠方法模式和簡單工廠模式在定義上的不一樣是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式, 把核心放在一個實類上。工廠方法模式能夠容許不少實的工廠類從抽象工廠類繼承下來, 從而能夠在實際上成爲多個簡單工廠模式的綜合,從而推廣了簡單工廠模式。
反過來說,簡單工廠模式是由工廠方法模式退化而來。設想若是咱們很是肯定一個系統只須要一個實的工廠類, 那麼就不妨把抽象工廠類合併到實的工廠類中去。而這樣一來,咱們就退化到簡單工廠模式了。
d、抽象工廠模式
代碼:
//抽象工廠類
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
//具體工廠類,其中Food,Vehicle,Weapon是抽象類,
public class DefaultFactory extends AbstractFactory{
@Override
public Food createFood() {
return new Apple();
}
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
}
//測試類
public class Test {
public static void main(String[] args) {
AbstractFactory f = new DefaultFactory();
Vehicle v = f.createVehicle();
v.run();
Weapon w = f.createWeapon();
w.shoot();
Food a = f.createFood();
a.printName();
}
}
在抽象工廠模式中,抽象產品 (AbstractProduct) 多是一個或多個,從而構成一個或多個產品族(Product Family)。 在只有一個產品族的狀況下,抽象工廠模式實際上退化到工廠方法模式。
6、總結。
(1)簡單工廠模式是由一個具體的類去建立其餘類的實例,父類是相同的,父類是具體的。
(2)工廠方法模式是有一個抽象的父類定義公共接口,子類負責生成具體的對象,這樣作的目的是將類的實例化操做延遲到子類中完成。
(3)抽象工廠模式提供一個建立一系列相關或相互依賴對象的接口,而無須指定他們具體的類。它針對的是有多個產品的等級結構。而工廠方法模式針對的是一個產品的等級結構。
單例對象(Singleton)是一種經常使用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。這樣的模式有幾個好處:
1、某些類建立比較頻繁,對於一些大型的對象,這是一筆很大的系統開銷。
2、省去了new操做符,下降了系統內存的使用頻率,減輕GC壓力。
3、有些類如交易所的核心交易引擎,控制着交易流程,若是該類能夠建立多個的話,系統徹底亂了。(好比一個軍隊出現了多個司令員同時指揮,確定會亂成一團),因此只有使用單例模式,才能保證核心交易服務器獨立控制整個流程。
首先咱們寫一個簡單的單例類:
[java] view plaincopy
1. public class Singleton {
2.
3. /* 持有私有靜態實例,防止被引用,此處賦值爲null,目的是實現延遲加載 */
4. private static Singleton instance = null;
5.
6. /* 私有構造方法,防止被實例化 */
7. private Singleton() {
8. }
9.
10. /* 靜態工程方法,建立實例 */
11. public static Singleton getInstance() {
12. if (instance == null) {
13. instance = new Singleton();
14. }
15. return instance;
16. }
17.
18. /* 若是該對象被用於序列化,能夠保證對象在序列化先後保持一致 */
19. public Object readResolve() {
20. return instance;
21. }
22. }
這個類能夠知足基本要求,可是,像這樣毫無線程安全保護的類,若是咱們把它放入多線程的環境下,確定就會出現問題了,如何解決?咱們首先會想到對getInstance方法加synchronized關鍵字,以下:
[java] view plaincopy
1. public static synchronized Singleton getInstance() {
2. if (instance == null) {
3. instance = new Singleton();
4. }
5. return instance;
6. }
可是,synchronized關鍵字鎖住的是這個對象,這樣的用法,在性能上會有所降低,由於每次調用getInstance(),都要對對象上鎖,事實上,只有在第一次建立對象的時候須要加鎖,以後就不須要了,因此,這個地方須要改進。咱們改爲下面這個:
[java] view plaincopy
1. public static Singleton getInstance() {
2. if (instance == null) {
3. synchronized (instance) {
4. if (instance == null) {
5. instance = new Singleton();
6. }
7. }
8. }
9. return instance;
10. }
1、最簡單的實現
首先,能想到的最簡單的實現是,把類的構造函數寫成private的,從而保證別的類不能實例化此類。而後在類中返回一個靜態示例並返回給調用者。這樣,調用者就能夠經過這個引用使用這個實例了。
public class Singleton{ private static final Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } private Singleton(){ }}
如上例,外部使用者若是須要使用SingletonClass的實例,只能經過getInstance()方法,而且它的構造方法是private的,這樣就保證了只能有一個對象存在。
2、性能優化--lazy loaded
上面的代碼雖然簡單,可是有一個問題----不管這個類是否被使用,都會建立一個instance對象。若是這個建立很耗時,好比說連接10000次數據庫(誇張一點啦....),而且這個類還不必定會被使用,那麼這個建立過程就是無用的,怎麼辦呢?
爲了解決這個問題,咱們想到的新的解決方案:
public class SingletonClass { private static SingletonClass instance = null; public static SingletonClass getInstance() { if(instance == null) { instance = new SingletonClass(); } return instance; } private SingletonClass() { } }
代碼的變化有倆處----首先,把 instance 設置爲 null ,知道第一次使用的時候判是否爲 null 來建立對象。由於建立對象不在聲明處,因此那個 final 的修飾必須去掉。
咱們來想象一下這個過程。要使用 SingletonClass ,調用 getInstance()方法,第一次的時候發現instance時null,而後就建立一個對象,返回出去;第二次再使用的時候,由於這個 instance事static的,共享一個對象變量的,因此instance的值已經不是null了,所以不會再建立對象,直接將其返回。
這個過程就稱爲lazy loaded ,也就是遲加載-----直到使用的時候才經行加載。
這樣寫法也比較完美:可是還能夠優化
public class SingletonClass{ private static SingletonClass instance = null; public static SingletonClass getInstance(){ if(instance == null){ synchronized(SingletonClass.class){ if(instance == null){ instance = new SingletonClass(); } } } return instance; } private SingletonClass(){ } }
經過單例模式的學習告訴咱們:
1、單例模式理解起來簡單,可是具體實現起來仍是有必定的難度。
2、synchronized關鍵字鎖定的是對象,在用的時候,必定要在恰當的地方使用(注意須要使用鎖的對象和過程,可能有的時候並非整個對象及整個過程都須要鎖)。
到這兒,單例模式基本已經講完了,結尾處,筆者忽然想到另外一個問題,就是採用類的靜態方法,實現單例模式的效果,也是可行的,此處兩者有什麼不一樣?
首先,靜態類不能實現接口。(從類的角度說是能夠的,可是那樣就破壞了靜態了。由於接口中不容許有static修飾的方法,因此即便實現了也是非靜態的)
其次,單例能夠被延遲初始化,靜態類通常在第一次加載是初始化。之因此延遲加載,是由於有些類比較龐大,因此延遲加載有助於提高性能。
再次,單例類能夠被繼承,他的方法能夠被覆寫。可是靜態類內部方法都是static,沒法被覆寫。
最後一點,單例類比較靈活,畢竟從實現上只是一個普通的Java類,只要知足單例的基本需求,你能夠在裏面爲所欲爲的實現一些其它功能,可是靜態類 不行。從上面這些歸納中,基本能夠看出兩者的區別,可是,從另外一方面講,咱們上面最後實現的那個單例模式,內部就是用一個靜態類來實現的,因此,兩者有很 大的關聯,只是咱們考慮問題的層面不一樣罷了。兩種思想的結合,才能造就出完美的解決方案,就像HashMap採用數組+鏈表來實現同樣,其實生活中不少事 情都是這樣,單用不一樣的方法來處理問題,老是有優勢也有缺點,最完美的方法是,結合各個方法的優勢,才能最好的解決問題!
工廠類模式提供的是建立單個類的模式,而建造者模式則是將各類產品集中起來進行管理,用來建立複合對象,所謂複合對象就是指某個類具備不一樣的屬性,其實建造者模式就是前面抽象工廠模式和最後的Test結合起來獲得的。咱們看一下代碼:
還和前面同樣,一個Sender接口,兩個實現類MailSender和SmsSender。最後,建造者類以下:
[java] view plaincopy
1. public class Builder {
2.
3. private List<Sender> list = new ArrayList<Sender>();
4.
5. public void produceMailSender(int count){
6. for(int i=0; i<count; i++){
7. list.add(new MailSender());
8. }
9. }
10.
11. public void produceSmsSender(int count){
12. for(int i=0; i<count; i++){
13. list.add(new SmsSender());
14. }
15. }
16. }
測試類:
[java] view plaincopy
1. public class Test {
2.
3. public static void main(String[] args) {
4. Builder builder = new Builder();
5. builder.produceMailSender(10);
6. }
7. }
從這點看出,建造者模式將不少功能集成到一個類裏,這個類能夠創造出比較複雜的東西。因此與工程模式的區別就是:工廠模式關注的是建立單個產品,而建造者模式則關注建立符合對象,多個部分。所以,是選擇工廠模式仍是建造者模式,依實際狀況而定。
原型模式雖然是建立型的模式,可是與工程模式沒有關係,從名字便可看出,該模式的思想就是將一個對象做爲原型,對其進行復制、克隆,產生一個和原對象相似的新對象。本小結會經過對象的複製,進行講解。在Java中,複製對象是經過clone()實現的,先建立一個原型類:
[java] view plaincopy
1. public class Prototype implements Cloneable {
2.
3. public Object clone() throws CloneNotSupportedException {
4. Prototype proto = (Prototype) super.clone();
5. return proto;
6. }
7. }
很簡單,一個原型類,只須要實現Cloneable接口,覆寫clone方法,此處clone方法能夠改爲任意的名稱,由於Cloneable接口 是個空接口,你能夠任意定義實現類的方法名,如cloneA或者cloneB,由於此處的重點是super.clone()這句 話,super.clone()調用的是Object的clone()方法,而在Object類中,clone()是native的,具體怎麼實現,我會 在另外一篇文章中,關於解讀Java中本地方法的調用,此處再也不深究。在這兒,我將結合對象的淺複製和深複製來講一下,首先須要瞭解對象深、淺複製的概念:
淺複製:將一個對象複製後,基本數據類型的變量都會從新建立,而引用類型,指向的仍是原對象所指向的。
深複製:將一個對象複製後,不管是基本數據類型還有引用類型,都是從新建立的。簡單來講,就是深複製進行了徹底完全的複製,而淺複製不完全。
此處,寫一個深淺複製的例子:
[java] view plaincopy
1. public class Prototype implements Cloneable, Serializable {
2.
3. private static final long serialVersionUID = 1L;
4. private String string;
5.
6. private SerializableObject obj;
7.
8. /* 淺複製 */
9. public Object clone() throws CloneNotSupportedException {
10. Prototype proto = (Prototype) super.clone();
11. return proto;
12. }
13.
14. /* 深複製 */
15. public Object deepClone() throws IOException, ClassNotFoundException {
16.
17. /* 寫入當前對象的二進制流 */
18. ByteArrayOutputStream bos = new ByteArrayOutputStream();
19. ObjectOutputStream oos = new ObjectOutputStream(bos);
20. oos.writeObject(this);
21.
22. /* 讀出二進制流產生的新對象 */
23. ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
24. ObjectInputStream ois = new ObjectInputStream(bis);
25. return ois.readObject();
26. }
27.
28. public String getString() {
29. return string;
30. }
31.
32. public void setString(String string) {
33. this.string = string;
34. }
35.
36. public SerializableObject getObj() {
37. return obj;
38. }
39.
40. public void setObj(SerializableObject obj) {
41. this.obj = obj;
42. }
43.
44. }
45.
46. class SerializableObject implements Serializable {
47. private static final long serialVersionUID = 1L;
48. }
要實現深複製,須要採用流的形式讀入當前對象的二進制輸入,再寫出二進制數據對應的對象。
咱們接着討論設計模式,上篇文章我講完了5種建立型模式,這章開始,我將講下7種結構型模式:適配器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。其中對象的適配器模式是各類模式的起源,咱們看下面的圖:
適配器模式將某個類的接口轉換成客戶端指望的另外一個接口表示,目的是消除因爲接口不匹配所形成的類的兼容性問題。主要分爲三類:類的適配器模式、對象的適配器模式、接口的適配器模式。首先,咱們來看看類的適配器模式,先看類圖:
核心思想就是:有一個Source類,擁有一個方法,待適配,目標接口時Targetable,經過Adapter類,將Source的功能擴展到Targetable裏,看代碼:
[java] view plaincopy
1. public class Source {
2.
3. public void method1() {
4. System.out.println("this is original method!");
5. }
6. }
[java] view plaincopy
1. public interface Targetable {
2.
3. /* 與原類中的方法相同 */
4. public void method1();
5.
6. /* 新類的方法 */
7. public void method2();
8. }
[java] view plaincopy
1. public class Adapter extends Source implements Targetable {
2.
3. @Override
4. public void method2() {
5. System.out.println("this is the targetable method!");
6. }
7. }
Adapter類繼承Source類,實現Targetable接口,下面是測試類:
[java] view plaincopy
1. public class AdapterTest {
2.
3. public static void main(String[] args) {
4. Targetable target = new Adapter();
5. target.method1();
6. target.method2();
7. }
8. }
輸出:
this is original method!
this is the targetable method!
這樣Targetable接口的實現類就具備了Source類的功能
將以前介紹的全部排序算法整理成NumberSort類,代碼
NumberSort
Java語言引入了Java虛擬機,具備跨平臺運行的功能,可以很好地適應各類Web應用。同時,爲了提升Java語言的性能和健壯性,還引入瞭如垃圾回收機制等新功能,經過這些改進讓Java具備其獨特的工做原理。
1.Java虛擬機
Java源程序經過編譯器編譯成.Class文件,而後java虛擬機中的java 解釋器負責將字節碼文件解釋成爲特定的機器碼進行運行。
java是一種半編譯半解釋型語言。半編譯是指:java源代碼,會通過javac命令變成 .class文件。半解釋是指: .class文件被jvm解釋的過程。也就是由於jvm的半解釋纔有了java的動態語言特性:反射和annotation。
和android區別
alvik有本身的libdex庫負責對.class進行處理。libdex主要對.class進行處理生成本身的dex文件。主要作的工做是,對虛擬機指令進行轉換(dalvik是基於寄存器的,sun虛擬機是基於棧的),對類的靜態數據進行歸類、壓縮。
dalvik基於寄存器,而JVM基於stack ,Dalvik執行的是特有的DEX文件格式,而JVM運行的是*.class文件格式。
優點:1、在編譯時提早優化代碼而不是等到運行時
2、 虛擬機很小,使用的空間也小;被設計來知足可高效運行多種虛擬機實例。
Java虛擬機的創建須要針對不一樣的軟硬件平臺來實現,既要考慮處理器的型號,也要考慮操做系統的種類。由此在SPARC結構、X86結構、MIPS和PPC等嵌入式處理芯片上,在UNIX、Linux、Windows和部分實時操做系統上均可實現Java虛擬機。
2.無用內存自動回收機制
而在Java運行環境中,始終存在着一個系統級的線程,專門跟蹤內存的使用狀況, 按期檢測出再也不使用的內存,並自動進行回收,避免了內存的泄露,也減輕了程序員的工做量。
1.JVM
JVM是Java平臺的核心,爲了讓編譯產生的字節碼能更好地解釋與執行,所以把JVM分紅了6個部分:JVM解釋器、指令系統、寄存器、棧、存儲區和碎片回收區。
能夠很明顯看出,Android系統架構由5部分組成,分別是:Linux Kernel、Android Runtime、Libraries、Application Framework、Applications。第二部分將詳細介紹這5個部分。
如今咱們拿起手術刀來剖析各個部分。其實這部分SDK文檔已經幫咱們作得很好了,咱們要作的就是拿來主義,而後再加上本身理解。下面自底向上分析各層。
Android基於Linux 2.6提供核心系統服務,例如:安全、內存管理、進程管理、網絡堆棧、驅動模型。Linux Kernel也做爲硬件和軟件之間的抽象層,它隱藏具體硬件細節而爲上層提供統一的服務。
Android 包含一個核心庫的集合,提供大部分在Java編程語言核心類庫中可用的功能。每個Android應用程序是Dalvik虛擬機中的實例,運行在他們本身 的進程中。Dalvik虛擬機設計成,在一個設備能夠高效地運行多個虛擬機。Dalvik虛擬機可執行文件格式是.dex,dex格式是專爲Dalvik 設計的一種壓縮格式,適合內存和處理器速度有限的系統。
大多數虛擬機包括JVM都是基於棧的,而Dalvik虛擬機則是基於寄存器的。 兩種架構各有優劣,通常而言,基於棧的機器須要更多指令,而基於寄存器的機器指令更大。dx 是一套工具,能夠將 Java .class 轉換成 .dex 格式。一個dex文件一般會有多個.class。因爲dex有時必須進行最佳化,會使文件大小增長1-4倍,以ODEX結尾。
Dalvik虛擬機依賴於Linux 內核提供基本功能,如線程和底層內存管理。
Android包含一個C/C++庫的集合,供Android系統的各個組件使用。這些功能經過Android的應用程序框架(application framework)暴露給開發者。下面列出一些核心庫:
· 系統C庫——標準C系統庫(libc)的BSD衍生,調整爲基於嵌入式Linux設備
· 媒體庫——基於PacketVideo的OpenCORE。這些庫支持播放和錄製許多流行的音頻和視頻格式,以及靜態圖像文件,包括MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG
· 界面管理——管理訪問顯示子系統和無縫組合多個應用程序的二維和三維圖形層
· LibWebCore——新式的Web瀏覽器引擎,驅動Android 瀏覽器和內嵌的web視圖
· SGL——基本的2D圖形引擎
· 3D庫——基於OpenGL ES 1.0 APIs的實現。庫使用硬件3D加速或包含高度優化的3D軟件光柵
· FreeType ——位圖和矢量字體渲染
· SQLite ——全部應用程序均可以使用的強大而輕量級的關係數據庫引擎
經過提供開放的開發平臺,Android使開發者可以編制極其豐富和新穎的應用程序。開發者能夠自由地利用設備硬件優點、訪問位置信息、運行後臺服務、設置鬧鐘、向狀態欄添加通知等等,不少不少。
開發者能夠徹底使用核心應用程序所使用的框架APIs。應用程序的體系結構旨在簡化組件的重用,任何應用程序都能發佈他的功能且任何其餘應用程序能夠使用這些功能(須要服從框架執行的安全限制)。這一機制容許用戶替換組件。
全部的應用程序實際上是一組服務和系統,包括:
· 視圖(View)——豐富的、可擴展的視圖集合,可用於構建一個應用程序。包括包括列表、網格、文本框、按鈕,甚至是內嵌的網頁瀏覽器
· 內容提供者(Content Providers)——使應用程序能訪問其餘應用程序(如通信錄)的數據,或共享本身的數據
· 資源管理器(Resource Manager)——提供訪問非代碼資源,如本地化字符串、圖形和佈局文件
· 通知管理器(Notification Manager)——使全部的應用程序可以在狀態欄顯示自定義警告
· 活動管理器(Activity Manager)——管理應用程序生命週期,提供通用的導航回退功能
Android裝配一個核心應用程序集合,包括電子郵件客戶端、SMS程序、日曆、地圖、瀏覽器、聯繫人和其餘設置。全部應用程序都是用Java編程語言寫的。更加豐富的應用程序有待咱們去開發!
1、Socket通訊簡介
Android 與服務器的通訊方式主要有兩種,一是Http通訊,一是Socket通訊。二者的最大差別在於,http鏈接使用的是「請求—響應方式」,即在請求時創建 鏈接通道,當客戶端向服務器發送請求後,服務器端才能向客戶端返回數據。而Socket通訊則是在雙方創建起鏈接後就能夠直接進行數據的傳輸,在鏈接時可 實現信息的主動推送,而不須要每次由客戶端想服務器發送請求。 那麼,什麼是socket?Socket又稱套接字,在程序內部提供了與外界通訊的端口,即端口通訊。經過創建socket鏈接,可爲通訊雙方的數據傳輸 傳提供通道。socket的主要特色有數據丟失率低,使用簡單且易於移植。
1.2Socket的分類
根據不一樣的的底層協議,Socket的實現是多樣化的。本指南中只介紹TCP/IP協議族的內容,在這個協議族當中主要的Socket類型爲流套接字 (streamsocket)和數據報套接字(datagramsocket)。流套接字將TCP做爲其端對端協議,提供了一個可信賴的字節流服務。數據 報套接字使用UDP協議,提供數據打包發送服務。
2、Socket 基本通訊模型
3、Socket基本實現原理
3.1基於TCP協議的Socket
服務器端首先聲明一個ServerSocket對象而且指定端口號,而後調 用Serversocket的accept()方法接收客戶端的數據。accept()方法在沒有數據進行接收的處於堵塞狀態。 (Socketsocket=serversocket.accept()),一旦接收到數據,經過inputstream讀取接收的數據。
客戶端建立一個Socket對象,指定服務器端的ip地址和端口號 (Socketsocket=newSocket("172.168.10.108",8080);),經過inputstream讀取數據,獲取服務器 發出的數據(OutputStreamoutputstream=socket.getOutputStream()),最後將要發送的數據寫入到 outputstream便可進行TCP協議的socket數據傳輸。
3.2基於UDP協議的數據傳輸
服務器端首先建立一個DatagramSocket對象,而且指點監聽的端 口。接下來建立一個空的DatagramSocket對象用於接收數據 (bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data,data.length)), 使用DatagramSocket的receive方法接收客戶端發送的數據,receive()與serversocket的accepet()相似, 在沒有數據進行接收的處於堵塞狀態。
客戶端也建立個DatagramSocket對象,而且指點監聽的端口。接 下來建立一個InetAddress對象,這個對象相似與一個網絡的發送地址 (InetAddressserveraddress=InetAddress.getByName("172.168.1.120")).定義要發送的 一個字符串,建立一個DatagramPacket對象,並制定要講這個數據報包發送到網絡的那個地址以及端口號,最後使用DatagramSocket 的對象的send()發送數據。*(Stringstr="hello";bytedata[]=str.getByte(); DatagramPacketpacket=new DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet);)
4、android 實現socket簡單通訊
4.1使用TCP協議通訊
android端實現:
[java] view plaincopy
1. protected void connectServerWithTCPSocket() {
2.
3. Socket socket;
4. try {// 建立一個Socket對象,並指定服務端的IP及端口號
5. socket = new Socket("192.168.1.32", 1989);
6. // 建立一個InputStream用戶讀取要發送的文件。
7. InputStream inputStream = new FileInputStream("e://a.txt");
8. // 獲取Socket的OutputStream對象用於發送數據。
9. OutputStream outputStream = socket.getOutputStream();
10. // 建立一個byte類型的buffer字節數組,用於存放讀取的本地文件
11. byte buffer[] = new byte[4 * 1024];
12. int temp = 0;
13. // 循環讀取文件
14. while ((temp = inputStream.read(buffer)) != -1) {
15. // 把數據寫入到OuputStream對象中
16. outputStream.write(buffer, 0, temp);
17. }
18. // 發送讀取的數據到服務端
19. outputStream.flush();
20.
21. /** 或建立一個報文,使用BufferedWriter寫入,看你的需求 **/
22. // String socketData = "[2143213;21343fjks;213]";
23. // BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
24. // socket.getOutputStream()));
25. // writer.write(socketData.replace("\n", " ") + "\n");
26. // writer.flush();
27. /************************************************/
28. } catch (UnknownHostException e) {
29. e.printStackTrace();
30. } catch (IOException e) {
31. e.printStackTrace();
32. }
33.
34. }
服務器端簡單實現:
[java] view plaincopy
1. public void ServerReceviedByTcp() {
2. // 聲明一個ServerSocket對象
3. ServerSocket serverSocket = null;
4. try {
5. // 建立一個ServerSocket對象,並讓這個Socket在1989端口監聽
6. serverSocket = new ServerSocket(1989);
7. // 調用ServerSocket的accept()方法,接受客戶端所發送的請求,
8. // 若是客戶端沒有發送數據,那麼該線程就停滯不繼續
9. Socket socket = serverSocket.accept();
10. // 從Socket當中獲得InputStream對象
11. InputStream inputStream = socket.getInputStream();
12. byte buffer[] = new byte[1024 * 4];
13. int temp = 0;
14. // 從InputStream當中讀取客戶端所發送的數據
15. while ((temp = inputStream.read(buffer)) != -1) {
16. System.out.println(new String(buffer, 0, temp));
17. }
18. serverSocket.close();
19. } catch (IOException e) {
20. e.printStackTrace();
21. }
22. }
4.2使用UDP協議通訊
客戶端發送數據實現:
[java] view plaincopy
1. protected void connectServerWithUDPSocket() {
2.
3. DatagramSocket socket;
4. try {
5. //建立DatagramSocket對象並指定一個端口號,注意,若是客戶端須要接收服務器的返回數據,
6. //還須要使用這個端口號來receive,因此必定要記住
7. socket = new DatagramSocket(1985);
8. //使用InetAddress(Inet4Address).getByName把IP地址轉換爲網絡地址
9. InetAddress serverAddress = InetAddress.getByName("192.168.1.32");
10. //Inet4Address serverAddress = (Inet4Address) Inet4Address.getByName("192.168.1.32");
11. String str = "[2143213;21343fjks;213]";//設置要發送的報文
12. byte data[] = str.getBytes();//把字符串str字符串轉換爲字節數組
13. //建立一個DatagramPacket對象,用於發送數據。
14. //參數一:要發送的數據 參數二:數據的長度 參數三:服務端的網絡地址 參數四:服務器端端口號
15. DatagramPacket packet = new DatagramPacket(data, data.length ,serverAddress ,10025);
16. socket.send(packet);//把數據發送到服務端。
17. } catch (SocketException e) {
18. e.printStackTrace();
19. } catch (UnknownHostException e) {
20. e.printStackTrace();
21. } catch (IOException e) {
22. e.printStackTrace();
23. }
24. }
客戶端接收服務器返回的數據:
[java] view plaincopy
1. public void ReceiveServerSocketData() {
2. DatagramSocket socket;
3. try {
4. //實例化的端口號要和發送時的socket一致,不然收不到data
5. socket = new DatagramSocket(1985);
6. byte data[] = new byte[4 * 1024];
7. //參數一:要接受的data 參數二:data的長度
8. DatagramPacket packet = new DatagramPacket(data, data.length);
9. socket.receive(packet);
10. //把接收到的data轉換爲String字符串
11. String result = new String(packet.getData(), packet.getOffset(),
12. packet.getLength());
13. socket.close();//不使用了記得要關閉
14. System.out.println("the number of reveived Socket is :" + flag
15. + "udpData:" + result);
16. } catch (SocketException e) {
17. e.printStackTrace();
18. } catch (IOException e) {
19. e.printStackTrace();
20. }
21. }
服務器接收客戶端實現:
[java] view plaincopy
1. public void ServerReceviedByUdp(){
2. //建立一個DatagramSocket對象,並指定監聽端口。(UDP使用DatagramSocket)
3. DatagramSocket socket;
4. try {
5. socket = new DatagramSocket(10025);
6. //建立一個byte類型的數組,用於存放接收到得數據
7. byte data[] = new byte[4*1024];
8. //建立一個DatagramPacket對象,並指定DatagramPacket對象的大小
9. DatagramPacket packet = new DatagramPacket(data,data.length);
10. //讀取接收到得數據
11. socket.receive(packet);
12. //把客戶端發送的數據轉換爲字符串。
13. //使用三個參數的String方法。參數一:數據包 參數二:起始位置 參數三:數據包長
14. String result = new String(packet.getData(),packet.getOffset() ,packet.getLength());
15. } catch (SocketException e) {
16. e.printStackTrace();
17. } catch (IOException e) {
18. e.printStackTrace();
19. }
20. }
5、總結:
使用UDP方式android端和服務器端接收能夠看出,其實android端和服務器端的發送和接收大庭相徑,只要端口號正確了,相互通訊就沒有問題,TCP使用的是流的方式發送,UDP是以包的形式發送。
本示例以Servlet爲例,演示Android與Servlet的通訊。
衆所周知,Android與服務器通訊一般採用HTTP通訊方式和Socket通訊方式,而HTTP通訊方式又分get和post兩種方式。至於Socket通訊會在之後的博文中介紹。
HTTP協議簡介:
HTTP (Hypertext Transfer Protocol ),是Web聯網的基礎,也是手機聯網經常使用的協議之一,HTTP協議是創建在TCP協議之上的一種協議。
HTTP鏈接最顯 著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。 在HTTP 1.0中,客戶端的每次請求都要求創建一次單獨的鏈接,在處理完本次請求後,就自動釋放鏈接。 在HTTP 1.1中則能夠在一次鏈接中處理多個請求,而且多個請求能夠重疊進行,不須要等待一個請求結束後再發送下一個請求。
由 於HTTP在每次請求結束後都會主動釋放鏈接,所以HTTP鏈接是一種「短鏈接」、「無狀態」,要保持客戶端程序的在線狀態,須要不斷地向服務器發起鏈接 請求。一般的作法是即便不須要得到任何數據,客戶端也保持每隔一段固定的時間向服務器發送一次「保持鏈接」的請求,服務器在收到該請求後對客戶端進行回 復,代表知道客戶端「在線」。若服務器長時間沒法收到客戶端的請求,則認爲客戶端「下線」,若客戶端長時間沒法收到服務器的回覆,則認爲網絡已經斷開。
基於HTTP1.0協議的客戶端在每次向服務器發出請求後,服務器就會向客戶端返回響應消息,在確認客戶端已經收到響應消息後,服務端就會關閉網絡鏈接。在這個數據傳輸過程當中,並不保存任何歷史信息和狀態信息,所以,HTTP協議也被認爲是無狀態的協議。
HTTP1.1 和HTTP1.0相比較而言,最大的區別就是增長了持久鏈接支持。當客戶端使用HTTP1.1協議鏈接到服務器後,服務器就將關閉客戶端鏈接的主動權交還 給客戶端;也就是說,只要不調用Socket類的close方法關閉網絡鏈接,就能夠繼續向服務器發送HTTP請求。
HTTP鏈接使用的是「請求—響應」的方式(2次握手),不只在請求時須要先創建鏈接,並且須要客戶端向服務器發出請求後,服務器端才能回覆數據。而Socket鏈接在雙方創建起鏈接後就能夠直接進行數據的傳輸
HTTP協議的特色:
支持B/S及C/S模式;
簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法經常使用的有GET、HEAD、POST。
靈活:HTTP 容許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type 加以標記;
無狀態:HTTP 協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺乏狀態意味着若是後續處理須要前面的信息,則它必須重傳,這樣可能致使每次鏈接傳送的數據量增大。
HTTP協議請求方法:
請求行中包括了請求方法,解釋以下:
GET 請求獲取Request-URI 所標識的資源;
POST 在Request-URI 所標識的資源後附加新的數據;
HEAD 請求獲取由Request-URI 所標識的資源的響應消息報頭
PUT 請求服務器存儲一個資源,並用Request-URI 做爲其標識
DELETE 請求服務器刪除Request-URI 所標識的資源;
TRACE 請求服務器回送收到的請求信息,主要用於測試或診斷
CONNECT 保留未來使用
OPTIONS 請求查詢服務器的性能,或者查詢與資源相關的選項和需求
Get與Post請求區別:
Post 請求能夠向服務器傳送數據,並且數據放在HTML HEADER內一塊兒傳送到服務端URL地址,數據對用戶不可見。而get是把參數數據隊列加到提交的URL中,值和表單內各個字段一一對應, 例如(http://www.baidu.com/s?w=%C4&inputT=2710)
get 傳送的數據量較小,不能大於2KB。post傳送的數據量較大,通常被默認爲不受限制。但理論上,IIS4中最大量爲80KB,IIS5中爲100KB。
get安全性很是低,post安全性較高。
在Android開發中咱們常常會用到網絡鏈接功能與服務器進行數據的交互,爲此Android的SDK提供了Apache的HttpClient來方便咱們使用各類Http服務
///
Get() 先建立一個HttpClient 而後再建立一個HttpGet,經過HttpClient的execute方法來發送一個HttpGet而且返回String內容。
try {
// 建立一個默認的HttpClient
HttpClient httpclient =new DefaultHttpClient();
// 建立一個GET請求
HttpGet request =new HttpGet("www.google.com");
// 發送GET請求,並將響應內容轉換成字符串
String response = httpclient.execute(request, new BasicResponseHandler());
Log.v("response text", response);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
///////////////////////////////
Post()
publicstatic String post(String url, NameValuePair... params) {
try {
// 編碼參數
List<NameValuePair> formparams =new ArrayList<NameValuePair>(); // 請求參數
for (NameValuePair p : params) {
formparams.add(p);
}
UrlEncodedFormEntity entity =new UrlEncodedFormEntity(formparams,
CHARSET);
// 建立POST請求
HttpPost request =new HttpPost(url);
request.setEntity(entity);
// 發送請求
HttpClient client = getHttpClient();
HttpResponse response = client.execute(request);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
thrownew RuntimeException("請求失敗");
}
HttpEntity resEntity = response.getEntity();
return (resEntity ==null) ?null : EntityUtils.toString(resEntity, CHARSET);
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (ClientProtocolException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (IOException e) {
thrownew RuntimeException("鏈接失敗", e);
}
}
整理:楊光福&王飛龍
時間倉促,不免有不周之處,請見諒。
http://www.cnblogs.com/pepcod/archive/2013/02/11/2937403.html
能夠用咱們上課講的說
也能夠參照
http://blog.saymagic.cn/2015/01/30/android-pic-three-cache.html
http://www.cnblogs.com/elliotta/p/3633752.html
http://blog.csdn.net/yudajun/article/details/9323941
技術方面說明
http://blog.csdn.net/lwyygydx/article/details/41870377
功能改進方面說明
http://digi.tech.qq.com/a/20150121/012030.htm
能夠參照李延磊老師的
也能夠參照連接
http://blog.csdn.net/fancylovejava/article/details/39927539
xUtils,Gson 極光推送 都講過,忽略
友盟第三方登陸
http://blog.umeng.com/uncategorized/4160.html
第三方登陸案例
http://blog.csdn.net/yueqinglkong/article/details/15028041
http://blog.csdn.net/lyf_007217/article/details/8542238
http://www.cnblogs.com/devinzhang/p/3856200.html
http://www.360doc.com/content/14/0402/09/10504424_365635496.shtml
http://blog.csdn.net/androidzhaoxiaogang/article/details/7910364
http://www.2cto.com/kf/201409/335964.html
http://blog.csdn.net/u200814499/article/details/40391443
http://blog.csdn.net/jiangliloveyou/article/details/9849775
http://blog.csdn.net/lnb333666/article/details/7471292
http://skywen.iteye.com/blog/1811310
已經講了,請看視頻
已經講了,請看視頻
已經講了,請看視頻
http://blog.csdn.net/wuqiong_524itcast/article/details/25378685
http://blog.csdn.net/wangshione/article/details/8490245
http://blog.csdn.net/lnb333666/article/details/8031770
1.垃圾收集算法的核心思想
Java語言創建了垃圾收集機制,用以跟蹤正在使用的對象和發現並回收再也不使用(引用)的對象。該機制能夠有效防範動態內存分配中因內存垃圾過多而引起的內存耗盡,以及不恰當的內存釋放所形成的內存非法引用。
垃圾收集算法的核心思想是:對虛擬機可用內存空間,即堆空間中的對象進行識別,若是對象正在被引用,那麼稱其爲存活對象,反之,若是對象再也不被引用,則 爲垃圾對象,能夠回收其佔據的空間,用於再分配。垃圾收集算法的選擇和垃圾收集系統參數的合理調節直接影響着系統性能,所以須要開發人員作比較深刻的瞭解。
2.觸發主GC(Garbage Collector)的條件
JVM進行次GC的頻率很高,但由於這種GC佔用時間極短,因此對系統產生的影響不大。更值得關注的是主GC的觸發條件,由於它對系統影響很明顯。總的來講,有兩個條件會觸發主GC:
①當應用程序空閒時,即沒有應用線程在運行時,GC會被調用。由於GC在優先級最低的線程中進行,因此當應用忙時,GC線程就不會被調用,但如下條件除外。
②Java堆內存不足時,GC會被調用。當應用線程在運行,並在運行過程當中建立新對象,若這時內存空間不足,JVM就會強制地調用GC線程,以 便回收內存用於新的分配。若GC一次以後仍不能知足內存分配的要求,JVM會再進行兩次GC做進一步的嘗試,若仍沒法知足要求,則 JVM將報「out of memory」的錯誤,Java應用將中止。
3.減小GC開銷的措施
根據上述GC的機制,程序的運行會直接影響系統環境的變化,從而影響GC的觸發。若不針對GC的特色進行設計和編碼,就會出現內存駐留等一系列負面影響。爲了不這些影響,基本的原則就是儘量地減小垃圾和減小GC過程當中的開銷。具體措施包括如下幾個方面:
(1)不要顯式調用System.gc()
此函數建議JVM進行主GC,雖然只是建議而非必定,但不少狀況下它會觸發主GC,從而增長主GC的頻率,也即增長了間歇性停頓的次數。
(2)儘可能減小臨時對象的使用
臨時對象在跳出函數調用後,會成爲垃圾,少用臨時變量就至關於減小了垃圾的產生,從而延長了出現上述第二個觸發條件出現的時間,減小了主GC的機會。
(3)對象不用時最好顯式置爲Null
通常而言,爲Null的對象都會被做爲垃圾處理,因此將不用的對象顯式地設爲Null,有利於GC收集器斷定垃圾,從而提升了GC的效率。
(4)儘可能使用StringBuffer,而不用String來累加字符串(詳見blog另外一篇文章JAVA中String與StringBuffer)
因爲String是固定長的字符串對象,累加String對象時,並不是在一個String對象中擴增,而是從新建立新的String對象,如 Str5=Str1+Str2+Str3+Str4,這條語句執行過程當中會產生多個垃圾對象,由於對次做「+」操做時都必須建立新的String對象,但 這些過渡對象對系統來講是沒有實際意義的,只會增長更多的垃圾。避免這種狀況能夠改用StringBuffer來累加字符串,因StringBuffer 是可變長的,它在原有基礎上進行擴增,不會產生中間對象。
(5)能用基本類型如Int,Long,就不用Integer,Long對象
基本類型變量佔用的內存資源比相應對象佔用的少得多,若是沒有必要,最好使用基本變量。
(6)儘可能少用靜態對象變量
靜態變量屬於全局變量,不會被GC回收,它們會一直佔用內存。
(7)分散對象建立或刪除的時間
集中在短期內大量建立新對象,特別是大對象,會致使忽然須要大量內存,JVM在面臨這種狀況時,只能進行主GC,以回收內存或整合內存碎片, 從而增長主GC的頻率。集中刪除對象,道理也是同樣的。它使得忽然出現了大量的垃圾對象,空閒空間必然減小,從而大大增長了下一次建立新對象時強制主GC 的機會。
gc()函數的做用只是提醒虛擬機:程序員但願進行一次垃圾回收。可是它不能保證垃圾回收必定會進行,並且具體何時進行是取決於具體的虛擬機的,不一樣的虛擬機有不一樣的對策。在Davilk中,給程序分配的內存是根據機型廠商的不一樣而不一樣(如今大部分爲32MB),在VM內部會將內存分爲:java使用的內存,Native使用的內存,他們之間不能共享,當某一方面不足
的時候必須向VM申請,而不能直接使用另一個的內存。
出現內存泄漏的可能性:
出現狀況:
1. 數據庫的cursor沒有關閉
2.構造adapter時,沒有使用緩存contentview
衍生listview的優化問題-----減小建立view的對象,充分使用contentview,能夠使用一靜態類來優化處理getview的過程
3.Bitmap對象不使用時採用recycle()釋放內存
4.activity中的對象的生命週期大於activity
調試方法: DDMS==> HEAPSZIE==>dataobject==>[Total Size]
1、 Android的內存機制
Android的程序由Java語言編寫,因此Android的內存管理與Java的內存管理類似。程序員經過new爲對象分配內存,全部對象在java 堆內分配空間;然而對象的釋放是由垃圾回收器來完成的。C/C++中的內存機制是「誰污染,誰治理」,java的就比較人性化了,給咱們請了一個專門的清 潔工(GC)
2、GC是什麼? 爲何要有GC?
GC是垃圾收集的意思(Gabage Collection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠 自動監測對象是否超過做用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操做方法。
4、垃圾回收器的基本原理是什麼?垃圾回收器能夠立刻回收內存嗎?有什麼辦法主動通知虛擬機進行垃圾回收?
對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對 象。經過這種方式肯定哪些對象是"可達的",哪些對象是"不可達的"。當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。能夠。程序員可 以手動執行System.gc(),通知GC運行,可是Java語言規範並不保證GC必定會執行。
間而忘記了釋放。若是程序中存在對無用對象的引用,那麼這些對象就會駐留內存,消耗內存,由於沒法讓垃圾回收器GC驗證這些對象是否再也不須要。若是存在對 象的引用,這個對象就被定義爲"有效的活動",同時不會被釋放。要肯定對象所佔內存將被回收,咱們就要務必確認該對象再也不會被使用。典型的作法就是把對象 數據成員設爲null或者從集合中移除該對象。但當局部變量不須要時,不需明顯的設爲null,由於一個方法執行完畢時,這些引用會自動被清理。
Java帶垃圾回收的機制,爲何還會內存泄露呢?舉例:
[java] view plaincopyprint?
1. Vector v = new Vector(10);
2. for (int i = 1; i < 100; i++) {
3. Object o = new Object();
4. v.add(o);
5. o = null;
6. }// 此時,全部的Object對象都沒有被釋放,由於變量v引用這些對象。
Java 內存泄露的根本緣由就是 保存了不可能再被訪問的變量類型的引用
6、Android的內存溢出
Android的內存溢出是如何發生的?
Android的虛擬機是基於寄存器的Dalvik,它的最大堆大小通常是16M,有的機器爲24M。也就是說咱們所能利用的內存空間是有限的。若是咱們的內存佔用超過了必定的水平就會出現OutOfMemory的錯誤。
爲何會出現內存不夠用的狀況呢?我想緣由主要有兩個:
因爲咱們程序的失誤,長期保持某些資源(如Context)的引用,形成內存泄露,資源形成得不到釋放。保存了多個耗用內存過大的對象(如Bitmap),形成內存超出限制。
(一)、(二)中,咱們瞭解了一些基本概念。
600dp的含義是:表明這個設備的最短的那一邊。
獲取設備的最短邊的代碼是:Configuration config = getResources().getConfiguration();
int smallestScreenWidth = config.smallestScreenWidthDp;
這個時候拿smallestScreenWidth 與600想比較就能夠知道該設備可否讀取裏面的資源了。
)
除此以外,爲了方便適配,在編碼時咱們還應該注意什麼呢,主要有如下幾點:
(1)多使用權重(android:layout_weight)
尤爲是在tab切換佈局,listview title及Item佈局等狀況下;
(2)設置寬度和高度時,儘可能使用match_parent和wrap_content,避免把控件寬高設死;
(3)父容器佈局選用
多使用RelativeLayout,FrameLayout,GridLayout等,減小布局層次。固然,在使用
權重時,得采用LinearLayout;
(4) 在xml裏,設置高度、寬度採用dp(dip),設置字體採用sp。
(應該注意,在代碼裏面,咱們寫的setHeight(...)單位是px)
(二)
那麼在具體開發中,咱們應該注意什麼呢。
首先,咱們必需要知道,其實適配的關鍵在於兩點:
(1)不一樣分辨率設備的適配,這點在單位的使用上用dp、sp以及圖片資源存放於不一樣的drawable文件夾就能夠解決問題;
(2)不一樣尺寸的適配,這點主要靠將相關值以及佈局文件放置於不一樣的文件夾中來解決。
2.1 values文件夾
能夠在工程下建立不一樣的values文件夾:values-sw480dp, values-sw600dp,
values-sw720dp-land等。好比一個控件的寬度,在10寸pad上是10dp,在8寸pad
上是5dp。這時,你能夠定義一個變量,button_width,而後在values-sw600dp
下寫5dp,在values-sw720-land下寫
10dp。這樣就達到了在不一樣尺寸pad上,
相應控件大小不同的效果。
2.1 layout文件夾
若是在不一樣尺寸設備上展現的佈局有明顯差異,僅僅用values不一樣已經難以控制,
那麼就能夠考慮寫不一樣的佈局文件置於不一樣的layout文件夾下,android會根據設備
尺寸去加載相應文件夾下的佈局文件。如:layout-sw480dp,layout-sw600dp,
layout-sw700dp等。
值得注意的是,若是不是頗有必要,儘可能採用2.1方案,方便維護。若是尺寸和分辨率都不一樣,
那麼就要結合(1)、(2)考慮了。
(補充:其實values文件夾和layout文件夾不只僅是根據尺寸判斷,也和分辨率有關,不過在一般狀況下,
綜合計算考慮,僅根據尺寸判斷就能夠了: