android 和 Java 知識點集錦
java 四種引用
強引用就是指在程式程式碼之中普遍存在的
軟引用是用來描述一些有用但並不是必需的物件,只有在記憶體不足的時候JVM才會回收該物件
弱引用也是用來描述非必需物件的,當JVM進行垃圾回收時,無論記憶體是否充足,都會回收被弱引用關聯的物件
虛引用和前面的軟引用、弱引用不同,它並不影響物件的生命週期。在java中用java.lang.ref.PhantomReference類表示。如果一個物件與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收。
要注意的是,虛引用必須和引用佇列關聯使用,當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會把這個虛引用加入到與之 關聯的引用佇列中。程式可以通過判斷引用佇列中是否已經加入了虛引用,來了解被引用的物件是否將要被垃圾回收。如果程式發現某個虛引用已經被加入到引用佇列,那麼就可以在所引用的物件的記憶體被回收之前採取必要的行動。
進一步理解軟引用和弱引用
對於強引用,我們平時在編寫程式碼時經常會用到。而對於其他三種類型的引用,使用得最多的就是軟引用和弱引用,這2種既有相似之處又有區別。它們都是用來描述非必需物件的,但是被軟引用關聯的物件只有在記憶體不足時才會被回收,而被弱引用關聯的物件在JVM進行垃圾回收時總會被回收。針對上面的特性,軟引用適合用來進行快取,當記憶體不夠時能讓JVM回收記憶體,弱引用能用來在回撥函式中防止記憶體洩露。因為回撥函式往往是匿名內部類,隱式儲存有對外部類的引用,所以如果回撥函式是在另一個執行緒裡面被回撥,而這時如果需要回收外部類,那麼就會記憶體洩露,因為匿名內部類儲存有對外部類的強引用。
java中堆和棧的區別
在函式中定義的一些基本型別的變數和物件的引用變數都在函式的棧記憶體中分配。
當在一段程式碼塊定義一個變數時,Java就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,Java會自動釋放掉為該變數所分配的記憶體空間,該記憶體空間可以立即被另作他用。
堆記憶體用來存放由new建立的物件和陣列。 在堆中分配的記憶體,由Java虛擬機器的自動垃圾回收器來管理。
在堆中產生了一個數組或物件後,還可以在棧中定義一個特殊的變數,讓棧中這個變數的取值等於陣列或物件在堆記憶體中的首地址,棧中的這個變數就成了陣列或物件的引用變數。 引用變數就相當於是為陣列或物件起的一個名稱,以後就可以在程式中使用棧中的引用變數來訪問堆中的陣列或物件。
java中變數在記憶體中的分配
1、類變數(static修飾的變數):在程式載入時系統就為它在堆中開闢了記憶體,堆中的記憶體地址存放於棧以便於高速訪問。靜態變數的生命週期--一直持續到整個"系統"關閉
2、例項變數:當你使用java關鍵字new的時候,系統在堆中開闢並不一定是連續的空間分配給變數(比如說類例項),然後根據零散的堆記憶體地址,通過雜湊演算法換算為一長串數字以表徵這個變數在堆中的"物理位置"。 例項變數的生命週期--當例項變數的引用丟失後,將被GC(垃圾回收器)列入可回收“名單”中,但並不是馬上就釋放堆中記憶體
3、區域性變數:區域性變數,由宣告在某方法,或某程式碼段裡(比如for迴圈),執行到它的時候在棧中開闢記憶體,當局部變數一但脫離作用域,記憶體立即釋放
附:java的記憶體機制
Java 把記憶體劃分成兩種:一種是棧記憶體,另一種是堆記憶體。
在函式中定義的一些基本型別的變數和物件的引用變數都是在函式的棧記憶體中分配,當在一段程式碼塊定義一個變數時,Java 就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,Java 會自動釋放掉為該變數分配的記憶體空間,該記憶體空間可以立即被另作它用。
堆記憶體用來存放由 new 建立的物件和陣列,在堆中分配的記憶體,由 Java 虛擬機器的自動垃圾回收器來管理。在堆中產生了一個數組或者物件之後,還可以在棧中定義一個特殊的變數,讓棧中的這個變數的取值等於陣列或物件在堆記憶體中的首地址,棧中的這個變數就成了陣列或物件的引用變數,以後就可以在程式中使用棧中的引用變數來訪問堆中的陣列或者物件,引用變數就相當於是為陣列或者物件起的一個名稱。引用變數是普通的變數,定義時在棧中分配,引用變數在程式執行到其作用域之外後被釋放。而陣列和物件本身在堆中分配,即使程式執行到使用 new 產生陣列或者物件的語句所在的程式碼塊之外,陣列和物件本身佔據的記憶體不會被釋放,陣列和物件在沒有引用變數指向它的時候,才變為垃圾,不能在被使用,但仍然佔據記憶體空間不放,在隨後的一個不確定的時間被垃圾回收器收走(釋放掉)。
這也是 Java 比較佔記憶體的原因,實際上,棧中的變數指向堆記憶體中的變數,這就是 Java 中的指標!
執行緒池的作用
在程式啟動的時候就建立若干執行緒來響應處理,它們被稱為執行緒池,裡面的執行緒叫工作執行緒 第一:降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。 第二:提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。 第三:提高執行緒的可管理性。 常用執行緒池:ExecutorService 是主要的實現類,其中常用的有 : Executors.newSingleThreadPool()
newFixedThreadPool()
newcachedTheadPool()
newScheduledThreadPool()
過載和重寫
過載: 在一個類中定義了多個名稱相同,而引數不同(引數的數量或型別或次序不同)的方法,則稱為方法的過載。
重寫: 子類中的方法與父類中的方法名稱相同,並且引數的個數與型別相同,返回值也相同,則成為方法的重寫。
注:過載是一個類的多型性表現,而重寫是子類與父類之間的一種多型性表現。
過載的規則: 1.必須改變引數列表(引數的數量或型別或次序不同);
2.可以改變返回值型別(是否過載與返回值型別無關);
3.可以改變訪問修飾符;
4.可以宣告新的或更廣的檢查異常;
5.最常用的就是構造方法的過載;
重寫的規則: 1.不可以改變引數列表;
2.不可以改變返回值型別;
3.訪問修飾符不能比父類中被重寫的方法的訪問許可權更低(public>protected>default>private);
4.不能丟擲新的強制性異常,不能丟擲比被重寫的方法宣告的更廣泛的強制性異常;
5.構造方法不能被重寫;
HashMap
1、HashMap與HashTable的區別
-
HashMap允許key和value為null;
-
HashMap是非同步的,執行緒不安全,也可以通過Collections.synchronizedMap()方法來得到一個同步的HashMap
-
HashMap存取速度更快,效率高
-
HashMap去掉了HashTable中的contains方法,加上了containsValue和containsKey方法
2、HashMap的實現原理
一句話理解HashMap:HashMap就是Hash表的Map實現。 Hash表就是Hash陣列,Map實現是指實現了Map介面。
HashMap的資料結構
HashMap的底層是基於陣列和連結串列實現的,儲存速度快的原因是因為它是通過計算雜湊碼來決定儲存的位置。HashMap中主要是通過key的hashCode來計算hash值的,只要hashCode相同,計算出來的hash值就一樣。如果儲存的物件對多了,就有可能不同的物件所算出來的hash值是相同的,這就出現了所謂的hash衝突。解決hash衝突的方法有很多,HashMap底層是通過連結串列來解決hash衝突的。