一、考虑用静态工厂方法替代构造函数

代表实现:java.util.Collection Framework

Boolean类的简单例子:

public static Boolean valueOf (boolean b){
return(b ? Boolean.TRUE: Boolean.FALSE);
}

优点:

1、与构造函数不同,静态工厂方法具有名字。

一个类看起来需要多个构造函数,并且它们的运行特征相同,应考虑使用静态工厂方法来替代其中一个或多个构造函数,并且要慎重选择它们的名字以明显标示他们的不同。

2、与构造函数不同,他们每次调用的时候,不要求非得创建一个新的对象。

当一个程序要频繁的创建相同的对象,并且创建对象的代价是昂贵的,这项技术可以极大地提高性能。

3、与构造函数不同,它们可以返回一个原返回类型的子类型的对象。

缺点:

1、类如果不含公有的或者受保护的构造函数,就不能被继承。

2、它们与其他的静态方法没有任何区别。

使用静态工厂方法要遵循命名习惯,其中两个已经很流行了

valueOf : 非常有效的类型转换符

getInstance : 返回实例,对于单例模式返回唯一的实例。

结论:构造函数和静态工厂要合理选择使用。

二、使用私有构造函数强化singleton属性

实现singleton有两种方法,这两种方法都要把构造函数保持为私有的,并且提供一个静态成员,以便能够允许客户访问该类的唯一实例

1、带有公有final域的方法

// Singleton with final field
public class Elvis{
public static final Elvis INSTANCE=new Elvis(); private Elvis(){ ……
}
……//Remained omitted
}

2、静态工厂方法

// Singleton with static factory
public class Elvis{
private static final Elvis INSTANCE=new Elvis(); private Elvis(){ ……
}
public static Elvis getInstance(){
return INSTANCE;
}
……//Remained omitted
}

如果确定永远是一个singleton,用第一种方法是有意义的,如果保留余地,让以后可以修改,使用第二种方法比价好。为了使一个singleton方法是可以序列化(serializable)的,仅仅在声明中加上"implements Serializable"是不够的。为了维护singleton性,必须加上一个readResolve方法,否则的话一个序列化的实例在反复序列化的时候,都会导致创建一个新的实例。为了防止这种情况在readResolve方法:

// readResolve 方法保持单例属性
private Object readResolve() throws ObjectStreamException{
/**
*返回真正的Elvis,让垃圾收集器注意假冒的Elvis
*/
}

三、通过私有构造函数强化不可实例化的能力

将一个类包含单个显示的私有构造函数,则它就不可以被实例化了:

//不可实例化的实体类
public class UtilityClass {
//不能实例化的抑制默认构造函数
private UtilityClass(){
//该构造函数将永远不能被调用
}
……//其余的省略
}

四、避免创建重复的对象

当你重用一已有对象的时候,请不要创建新的对象,而同样的,当你创建一个新的对象的时候,请不要重用一个已有对象。在提倡使用保护行拷贝的场合,因重用一个对象儿招致的代价要远远大于因创建重复对象而招致的代价。在要求保护性拷贝的情况下却没有实施保护性拷贝,将会导致错误和安全漏洞;而不必要的创建对象仅仅会影响程序的风格和性能。

五、消除过期的对象引用

考虑下面栈实现的例子,你能否发现内存泄露的位置:

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);
}
}
}

从栈中弹出来的对象将不会当做垃圾回收,即使使用栈的客户程序不再引用这些对象,它们将不会回收。这是因为,栈内部维护这对这些对象的过期引用(过期引用,即永远也不会再被解除的引用),本例中凡是elements数组活动区域之外的引用都是过期的,elements的活动区域是指下标小于size的那一部分。

要想修复该问题很简单,一旦对象引用已经过期,只需要清空这些引用即可。pop方法的修订版如下:

public Object pop() {
if (size==0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // 删除过期引用
return result;
}

“清空度对象引用”这样的操作应该是一个例外,而不是一种规范行为。消除过期引用最好的办法是重用一个本来已经包含对象引用的变量,或者让这个 变量结束期声明周期。何时清除一个引用,Stack哪方面的特性使得它遭受到了内存泄露的影响?

根源在于Stack自己管理内存,存储池包含了elements数组(对象引用单元,而不是引用本身)的元素。数组活动区域中的元素是已分配的,而数组其余部分的元素是自由的。但垃圾回收器不知道,需要程序员手动清空。

六、避免使用终结函数

显示的终止方法通常与try-finally结构结合起来使用,以确保及时终止。

// try-finally 块保证终结方法的执行
Foo foo = new Foo(...);
try {
// 对fool执行一些必须操作
...
} finally {
foo.terminate(); // 显示终结方法
}

另一种方法是“终结函数链(finalizeer chaining)”不会自动执行,如果一个类(不是Object类)有一个终结函数,并且只有一个子类改写了终结函数,那么子类的终结函数必须手工调用父类的终结函数。

 // 手工终结链
protected void finalize() throws Throwable {
try {
// 终结子类的状态
...
} finally {
super.finalize();
}
}

即使子类的终结过程中跑出一个异常,超类的终结函数也会被执行,反之亦然。
但是如果子类改写了超累的终结函数,但是忘记调用超累的终结函数(或者有意不调用),会使得超类的终结函数永远得不到执行。为了解决这一问题,我们使用匿名类的单个实例(即终结函数守卫者)来终结其外围实例。

// 终结函数守卫者
public class Foo {
// 此对象的唯一目的是终结微微的Fool对象
private final Object finalizerGuardian = new Object() {
protected void finalize() throws Throwable {
// 终结外围的 Foo 对象
...
}
}; // 匿名类
... // 余下省略
}

公有类Fool并没有终结函数(除了它从Object中继承了一个无关紧要的finalize之外),所以子类的终结函数是否调用super.finalize并不重要,对于每一个带有终结函数的公有非final类,都应该考虑使用这项技术。

Java高效编程之一【创建和销毁对象】的更多相关文章

  1. Effective Java(1)-创建和销毁对象

    Effective Java(1)-创建和销毁对象

  2. effective java 第2章-创建和销毁对象 读书笔记

    背景 去年就把这本javaer必读书--effective java中文版第二版 读完了,第一遍感觉比较肤浅,今年打算开始第二遍,顺便做一下笔记,后续会持续更新. 1.考虑用静态工厂方法替代构造器 优 ...

  3. 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器

    类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...

  4. Effective Java——(一)创建和销毁对象

    第一条 考虑用静态工厂方法代替构造器 什么叫静态工厂方法,就是通过在类中通过静态方法对对象初始化. 比如说 public class StaticFactory { private String na ...

  5. Effective Java 读书笔记之一 创建和销毁对象

    一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...

  6. Effective Java 学习笔记之创建和销毁对象

    一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法 ...

  7. 【Effective Java】第二章-创建和销毁对象——1.考虑用静态工厂方法代替构造器

    静态工厂方法的优点: 可以赋予一个具有明确含义的名称 可以复用唯一实例,不必每次新建 可以返回原实例类型的子类对象 可以在返回泛型实例时更加简洁 缺点: 类如果不含有共有的或者受保护的构造器,就不能被 ...

  8. Effective Java(一)—— 创建和销毁对象

    在客户端(调用端)获取自身实例的方法: 公有的构造器: 类的静态工厂方法: 1. 使用静态工厂方法代替构造器 Boolean 是对基本类型 boolean 的包装类: public final cla ...

  9. 《Effective Java》—— 创建与销毁对象

    本篇主要总结的是<Effecticve Java>中关于创建和销毁对象的内容. 比如: 何时以及如何创建对象 何时以及如何避免创建对象 如何确保及时销毁 如何管理对象销毁前的清理动作 考虑 ...

  10. effective java读书小记(一)创建和销毁对象

    序言 <effective java>可谓是java学习者心中的一本绝对不能不拜读的好书,她对于目标读者(有一点编程基础和开发经验)的人来说,由浅入深,言简意赅.每一章节都分为若干的条目, ...

随机推荐

  1. android监听屏幕打开关闭广播无响应的情况

    android在屏幕打开和关闭的时候会发出广播,但是如果receiver配置在AndroidManifest.xml中时,receiver是接受不到任何广播的. <receiver androi ...

  2. 怎么用sql语句查询一个数据库有多少张表

    今天在技术群中闲谈时忽然聊到一个问题,那就是当一个数据库中有多张表时怎么快速的获取到表的个数,从而给问询者一个准确的回答. 大家或许会说,这个问题和我们的数据库操作没有太大关系或者不是很挂钩,所以没意 ...

  3. PySe-003-Se-WebDriver 启动浏览器之一 - Firefox

    此文主要演示 MacOX 下 WebDriver 启动 Firefox 浏览器,因 WebDriver 对 Firefox 浏览器是原生支持的,因而无需像启动其他浏览器一样需要相对应的 driver. ...

  4. JavaScript实现在textbox输入时自动去数据库匹配并找出类似值列出,选择后记得将值填入本textbox及下一个textbox

    1. <script src='<%= Application["rootURL"] %>JS/jquery-1.4.1.min.js' type="t ...

  5. 什么是EBC和EBO

    EBC英文全称为“Empty Base Class”,中文全称“空基类”.那什么是空基类呢?简单的说就是没有任何数据成员的类就称之为空基类.也就是EBC的类定义中不包含任何数据成员,那么这样一来可能大 ...

  6. SqlServer基础:类型转换Cast和Convert

    在SqlServer要对不同类型的数据进行运算时,需要将其转换为相同类型之后再做操作,而SqlServer中有两个函数可以进行数据转换,即:Cast和Convert 1.Cast CAST(expre ...

  7. dom core,html dom,css dom,jquery 中的dom操作

    前端开发中为达到某种目的,往往有很多方法:dom core,html dom,jquery; dom core/jquery主要通过函数调用的方式(getAttribute("属性名&quo ...

  8. NETBEANS + XDEBUG + IIS PHP 代码 调试 DEBUG

    参考: http://domainwebcenter.com/?p=936 http://www.sitepoint.com/debugging-and-profiling-php-with-xdeb ...

  9. HTML页面刷新、跳转

    HTML方式 1.页面刷新 <!-- 5秒之后,跳转到http://www.qunar.com页面 --> <meta http-equiv="refresh" ...

  10. Fiddler 的Window 8.1中不可以正常工作

    昨天晚上新升级了操作系统至Windows 8.1 Pro,发现使用Fiddler时网站不能正常使用,导致“代理错误”等信息. 解决方案: http://fiddler2.com/blog/blog/2 ...