首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

其次天和第三天(第4-6条)

2013-11-08 
第二天和第三天(第4-6条)?把第二天和第三天的阅读内容补上《Effective java》中的第4-6条?第4条:避免创建重

第二天和第三天(第4-6条)

?

把第二天和第三天的阅读内容补上《Effective java》中的第4-6条

?

第4条:避免创建重复的对象

反面的例子:

?

String s = new String("anson");

?传递给String的实参“anson”本身就是一个String的实例,如果这个语句出现在循环语句中或者是会被频繁的调用,那么会创建出很多不必要的对象。

一个改进的版本:

?

String s = "anson";

?这个版本只使用一个S t r i n g实例,而不是每次被执行的时候创建一个新的实例。而且,它可以保证,对于所有在同一个虚拟机中运行的代码,只要它们包含相同的字符串字面常量,则该对象就会被重用[JLS, 3.10.5]。

?

对于同时提供静态工厂方法和构造函数的非可变类,通常是利用静态工厂方法而不是构造函数,以避免创建重复的对象。例如Boolean.valueOf(String),一般要优先于Boolean(String).

?

不要错误地认为本条目所介绍的内容暗示着“创建对象的代价是非常昂贵的,我们应该要尽可能地避免创建对象”。相反,由于小对象的构造函数只做很少量的工作,所以,小对象的创建和回收动作是非常廉价的,特别是在现代的J V M实现上更是如此。通过创建附加的对象,以使得一个程序更加清晰、简洁、功能强大,这往往也是一件好事。

?

通常自己维护对象池不是一种好选择,除非池中的对象是非常重量级的,例如数据库连接池,IO流等。现代的jvm有高度优化的垃圾回收器,性能很容易超过轻量级对象池的性能。

?

第5条:消除过期的对象引用

一个简单的栈实现例子:

?

public class stack {    private Object[] elements;    private int size = 0;    public Stack(int initialCapacity) {        this.elements = new Object[initialCapacity];    }    public void push(Object e) {        ensureCapacity();        elements[size++] = e;    }    public Object pop() {        if (size == 0)            throw new EmptyStackException();        return elements[--size];    }    private void ensureCapacity() {        if (elements.length == size) {            Object[] oldElements = elements;            elements = new Object[2 * elements.length +1];            System.arraycopy(oldElements,0,elements,0,size);        }    }}

这段程序严格来讲存在”内存泄露“:如果一个栈先是增长,然后再收缩,那么从栈弹出来的对象将不会被当做垃圾回收,即使使用栈的客户程序不再引用这些对象,它们也不会被回收。因为,栈内部维护者对这些对象的国旗引用。所谓国旗引用,是指永远不会再被解除的引用。

想修复这类问题也很简单:一旦对象引用已经过期,只需清空这些引用即可。在上诉的例子中,只要一个单元被弹出栈,指向它的引用就过期了。pop方法的修订版本如下:

public Object pop() {    if (size == 0)        throw new EmptyStackException();    Object result = elements[--size];    elements[size] = null;    return result;}

?第6条:避免使用终结函数

终结函数(finalizer)通常是不可预测的,常常也是很危险的,一般情况下是不必要的。

终结函数并不能保证会被及时地执行[JLS,12.6]。从一个对象变得不可到达开始,到它的终结函数被执行,这段时间可以使任意的、不确定的。当我们在终结函数中释放关键资源例如文件操作,可能会造成很严重的后果。

JLS不仅不保证终结函数会被及时地执行,而且根本就不保证它们会被执行。

不要被System.gc和System.runFinalization这两个方法迷惑,它们确实能增加终结函数被执行的机会,但是它们并不保证终结函数一定会被执行。

如果一个类封装的资源确实需要回收,我们需要提供一个显示的终止方法,并要求类的客户在每个实例不再有用的时候调用这个方法。典型的例子是InputStream和OutputStram的close方法。

热点排行