1 重点关注
1.1 通用方法避免过期对象的应用
消除过期引用的最好方法是让包含该引用的变量结束其生命周期。
如果使用最紧凑作用域范围定义每一个变量,这种情形自然而然的发生
1.2 消除过期对象的使用场景
a 栈的pop,需要我们手动清空,因为栈类自己管理内存
b 随着时间推移,过期缓存可以使用后台线程来完成消除(可以用定时器); 如果缓存之外存在某项键的外部引用,也可以用WeakHashMap
c 监听器和其他回调(如果使用HashMap的话),可以使用弱引用参考3.3,相关案例可以参考
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");
}
}