Effective Java 2
uwupu 啦啦啦啦啦

6. 避免创建不必要的对象

最好能重用单个对象,而不是每次需要的时候就创建一个相同功能的新对象;

可以提高效率。

String避免多次创建对象

错误的做法:

1
String s = new String("It's a text.");

每次执行的时候都会创建一个String对象,而且参数("It's a text.")本来就是一个对象,这样使用会影响效率;

如果在一个频繁调用的方法中出现,就会创建成千上万个对象;

正确的做法:

1
String s= "It's a text.";

这样就只使用了一个String实例,而不是每次运行都会创建一个示例;

在JVM里这样做,对于不同的String引用,如果它们的字符串是相同的,它们对应对象就是一样的,而不是多个对象。

对于提供了静态工厂方法的类,一般优先使用静态工厂方法而非构造器。

如使用Boolean.valueOf()而不是Boolean()

有些对象创建成本较高,如果内容不变,可以考虑将这些对象缓存下来多次使用。

比如Pattern实例;

Pattern实例创建成本较高,若多次创建对性能影响较大;

可以考虑将正则表达式显式地编译成一个Pattern实例,并让他成为类初始化的一部分;

1
private final static Pattern pattern = Pattern.compile(">(.*)<\/div>")

优先使用基本类型而非装箱基本类型

使用基本类型比装箱基本类型效率较高,因为装箱基本类型需要创建对象;

错误的做法:

1
2
3
4
5
6
7
8
9
public class 使用基本数据类型而非装箱基本类型 {
public static void main(String[] args) {
Long res = 0L;
for (int i = 0 ; i < Integer.MAX_VALUE ; i++){
res += i;
}
System.out.println(res);
}
}

正确的做法:只需要将Long改为long就可。

1
2
3
4
5
6
7
8
9
public class 使用基本数据类型而非装箱基本类型 {
public static void main(String[] args) {
long res = 0L;
for (int i = 0 ; i < Integer.MAX_VALUE ; i++){
res += i;
}
System.out.println(res);
}
}

7. 消除过期的对象引用

使用栈来学习“无意识的内存泄露”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Stack {
private Object[] elements;//栈内引用
private int size = 0;//当前大小
private static final int DEFAULT_INITIAL_CAPACITY = 16;//默认初始化容量


public Stack(){
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}

//向栈中添加内容
public void push(Object e){
ensureCapacity();
elements[size++] = e;
}

//从栈中取出内容
public Object pop(){
if (size==0)throw new EmptyStackException();
return elements[--size];
//当size--,旧的对象并没有被清理,如果对象很大且很多,就会引发内存泄露
}

//确保容量,如果数组大小不够了,就扩容。
public void ensureCapacity(){
if (elements.length == size){
elements = Arrays.copyOf(elements,2*size+1);
}
}

}

如果栈内元素先push,然后pop,旧的对象并没有被清理,且由于被引用,不会被gc清理掉。

有概率引发内存泄漏;

解决方法:

1
2
3
4
5
6
public Object pop(){
if (size==0)throw new EmptyStackException();
Object o = elements[--size];//先取出对象
elements[size] = null;//将数组内引用清除
return o;
}

先取出对象,将数组内引用清除,这样就不会引用对象,最后返回对象;

若对象在后续过程中使用结束,对象将会被gc清理,而不是无法被清理。

为缓存设置生命周期

监听器和其他回调

为API回调使用WeakHashMap

如果实现了一个API,客户端在这个API进行注册回调,却没有显式地取消注册,这样的注册会逐渐堆积起来,引发可能的内存泄漏;

确保回调被回收的方法就是只保存他们的弱引用,比如将他们保存成WeakHashMap的键。

 评论