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"); } }
诸葛