1 重點關注
1.1 通用方法避免過期對象的應用
消除過期引用的最好方法是讓包含該引用的變量結束其生命週期。
如果使用最緊湊作用域範圍定義每一個變量,這種情形自然而然的發生
1.2 消除過期對象的使用場景
a 棧的pop,需要我們手動清空,因爲棧類自己管理內存
b 隨着時間推移,過期緩存可以使用後臺線程來完成消除(可以用定時器); 如果緩存之外存在某項鍵的外部引用,也可以用WeakHashMap
c 監聽器和其他回調(如果使用HashMap的話),可以使用弱引用參考3.3,相關案例可以參考https://blog.csdn.net/weixin_36410904/article/details/114160943
2 課程內容
2.1 數組屬於棧還是隊列?棧和隊列的區別
答:靜態數組,List存儲於棧上
棧是先進後出,有底的瓶子
隊列是先進先出,無底的瓶子
有了這個基礎,再看3.1
棧:有編譯器自動分配和釋放,存放函數的參數、局部變量、臨時變量、函數返回地址等;
2.2 實時設置數組的大小
見3.1的 ensurCapacity 方法
2.3 重要關注
參見1
3 代碼演練
3.1 棧的彈出未消除過期對象(反例)
棧:
package com.ddwei.test.core.chapter6.demo1; import java.util.Arrays; import java.util.EmptyStackException; public class Stack { private Object[] elements; private static final int DEFALUT_INITIAL_CAPACITY = 4; private int size = 0; public Stack(){ elements = new Object[DEFALUT_INITIAL_CAPACITY ]; } /** * 棧移入元素 * @author weidoudou * @date 2022/6/27 12:52 * @param obj 請添加參數描述 * @return void **/ public void push(Object obj){ // ensurCapacity(); elements[size++] = obj; } /** * 棧移除元素 * @author weidoudou * @date 2022/6/27 12:51 * @param * @return java.lang.Object **/ public Object pop(){ if(size == 0){ throw new EmptyStackException(); } return elements[--size]; } /** * 預先設置數組的大小,每次數組元素不夠的時候,進行擴充兩倍 * @author weidoudou * @date 2022/6/27 12:49 * @param * @return void **/ public void ensurCapacity(){ if(elements.length == size){ elements = Arrays.copyOf(elements,2*size+1); } } }
測試類:
package com.ddwei.test.core.chapter6.demo1; public class StackTest { public static void main(String[] args) { Stack stack = new Stack(); stack.push("0"); stack.push("1"); stack.push("2"); stack.push("3"); stack.push("4"); stack.pop(); } }
3.2 棧的彈出消除過期對象(正例)
棧:(着重看 elements[size] = null;)
package com.ddwei.test.core.chapter6.demo2; import java.util.Arrays; import java.util.EmptyStackException; public class Stack2 { private Object[] elements; private static final int DEFALUT_INITIAL_CAPACITY = 16; private int size = 0; public Stack2(){ elements = new Object[DEFALUT_INITIAL_CAPACITY ]; } /** * 棧移入元素 * @author weidoudou * @date 2022/6/27 12:52 * @param obj 請添加參數描述 * @return void **/ public void push(Object obj){ // ensurCapacity(); elements[size++] = obj; } /** * 棧移除元素 * @author weidoudou * @date 2022/6/27 12:51 * @param * @return java.lang.Object **/ public Object pop(){ if(size == 0){ throw new EmptyStackException(); } Object result = elements[--size]; elements[size] = null; return result; } /** * 預先設置數組的大小,每次數組元素不夠的時候,進行擴充兩倍 * @author weidoudou * @date 2022/6/27 12:49 * @param * @return void **/ public void ensurCapacity(){ if(elements.length == size){ elements = Arrays.copyOf(elements,2*size+1); } } }
測試類:
package com.ddwei.test.core.chapter6.demo2; import com.ddwei.test.core.chapter6.demo1.Stack; public class StackTest2 { public static void main(String[] args) { Stack2 stack = new Stack2(); stack.push("0"); stack.push("1"); stack.push("2"); stack.push("3"); stack.push("4"); stack.pop(); } }
3.3 弱引用demo
demo
package com.ddwei.test.core.chapter6.demo3; import java.lang.ref.WeakReference; public class App { public static WeakReference<String> weakReference1; public static void main(String[] args) { test1(); //test1外部,hello對象作用域結束,沒有強引用指向"value"了。只有一個弱引用指向"value" System.out.println("未進行gc時,只有弱引用指向value內存區域:" + weakReference1.get()); //此時gc時會回收弱引用 System.gc(); //此時輸出都爲nuill System.out.println("進行gc時,只有弱引用指向value內存區域:" + weakReference1.get()); } public static void test1() { //hello對象強引用"value" String hello = new String("value"); //weakReference1對象弱引用指向"value" weakReference1 = new WeakReference<>(hello); //在test1內部調用gc,此時gc不會回收弱引用,因爲hello對象強引用"value" System.gc(); System.out.println("進行gc時,強引用與弱引用同時指向value內存區域:" + weakReference1.get()); } }
打印日誌
進行gc時,強引用與弱引用同時指向value內存區域:value 未進行gc時,只有弱引用指向value內存區域:value 進行gc時,只有弱引用指向value內存區域:null Process finished with exit code 0
3.4 List的Remove方法不需要消除過期對象
demo
package com.ddwei.test.core.chapter6.demo4; import java.util.ArrayList; import java.util.List; public class ListTest { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("aaa"); list.remove("aaa"); } }