第5条:避免创建不必要的对象

本条主要讲的是一些反面教材,希望大家引以为鉴。

①无意中使用自动装箱导致多创建对象。

public class Sum {
public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
}

sum被声明为Long而不是long,意味着每次i都要被自动装箱(创建Long实例),因此速度会慢很多。

②可以重用不会被修改的可变对象。

也就是说,有些看起来是变量,但是实际上它的值一旦计算出来之后就不再变化,这种也应该视作常量,而不是每次都计算。

下面先看一段代码。

public class Person {
//生日
private final Date birthDate; public Person(Date birthDate) {
this.birthDate = new Date(birthDate.getTime());
} public boolean isBabyBoomer() {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
//婴儿潮开始时间
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
//婴儿潮结束时间
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0
&& birthDate.compareTo(boomEnd) < 0;
}
}

这段代码中的isBabyBoomer方法,根据生日判断是否属于婴儿潮时间。看起来并没有什么问题。

但实际上,每次调用这个方法时,都会新建一个Calendar,一个TimeZone和两个Date实例,这是没有必要的(所以,在平时写方法时也要注意,有很多对象是可以提取出来的)。下面看如何改进。

public class Person {
private final Date birthDate; public Person(Date birthDate) {
this.birthDate = new Date(birthDate.getTime());
}
private static final Date BOOM_START;
private static final Date BOOM_END; static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
} public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0
&& birthDate.compareTo(BOOM_END) < 0;
}
}

改进之后Person类仅在初始化时创建了实例,后面调用isBabyBoomer方法时,就没有生成对象的消耗了。

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

下面的例子对java中的栈进行一个简单的模拟,看起来逻辑上没什么问题,却隐藏着一个问题。

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();
Object result = elements[--size];
//如果没有这一步,会产生很大的问题
//elements[size] = null;
return result;
} private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}

问题就在于,当栈先增长,然后再收缩。从栈中弹出来的对象并不会被当做垃圾回收,这是因为栈内还维护着这些对象的引用。弹出之后,使用栈的程序不再需要它,只能人为清理掉。一般而言,只要类是自己管理内存,程序员就应该警惕内存泄漏问题。

文中还还提到在使用回调时,确保回调立即被当作垃圾回收的最佳方法时只保存它们的弱引用,例如,只将它们保存成WeakHashMap中的键(这个平时很少用到,只作为了解)。

弱引用与强引用的区别在于,即使内存不足,强引用也不会被回收掉。而弱引用不管内存足不足,一旦被垃圾回收线程发现,就会被回收掉。

Effective Java2读书笔记-创建和销毁对象(三)的更多相关文章

  1. Effective Java2读书笔记-创建和销毁对象(一)

    第1条:考虑用静态工厂方法代替构造器 通常情况下,我们创建一个对象采取new的形式,但是还有一种方法也是经常使用到的,它的名称叫做静态工厂方法. 例如,java中基本类型boolean的包装类Bool ...

  2. Effective Java2读书笔记-创建和销毁对象(四)

    第7条:避免使用终结方法 这一条讲的简直是不知所云.先简单记下来其中说出的几条: ①显式终止方法的典型例子有InputStream.OutputStream和java.sql.Connection上的 ...

  3. Effective Java2读书笔记-创建和销毁对象(二)

    第3条:用私有构造器或者枚举类型强化Singleton属性 这一条,总体来说,就是讲了一个小技巧,将构造器声明为private,可以实现单例.具体有以下几种实现的方式. ①最传统的单例实现模式,可能有 ...

  4. Effective Java读书笔记--创建和销毁对象

    1.优先考虑用静态工厂方法代替构造器2.遇到多个构造器参数时要考虑使用构建器Builder解决参数过多,不可变类型.私有构造方法,静态类的构造方法提供必要参数,剩下可选.new xxx.build() ...

  5. Effective Java学习笔记--创建和销毁对象

    创建和销毁对象 一.静态工厂方法代替构造器 静态工厂方法的优缺点 优点: 1.可以自定义名称(可以将功能表述的更加清晰) 2.不必每次调用都创建新的对象(同一对象重复使用) 3.返回的类型可以是原返回 ...

  6. Effective Java2读书笔记-类和接口(三)

    第17条:要么为继承而设计,并提供文档说明,要么就禁止继承 第18条:接口优于抽象类 这两条中,提到了一个很重要的概念骨架实现.也就是说,抽象类实现接口的形式.这样的好处是,接口本来不能提供默认的实现 ...

  7. [Effective Java]第二章 创建和销毁对象

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  8. Effective Java2读书笔记-对于所有对象都通用的方法(二)

    第10条:始终要覆盖toString 这一条没什么好讲的,就是说默认的toString方法打印出来的是类名+@+十六进制哈希码的值.我们应该覆盖它,使它能够展示出一些更为详细清晰的信息,这个看实际情况 ...

  9. Effective Java2读书笔记-对于所有对象都通用的方法(一)

    第8条:覆盖equals时请遵守通用约定 ①约定的内容 自反性.对于任何非null的引用值x.x.equals(x)必须返回true. 对称性.对于任何非null的引用值x和y.当且仅当y.equal ...

随机推荐

  1. Spoj1771-Yet Another N-Queen Problem(精确覆盖)

    Description After solving Solution to the n Queens Puzzle by constructing, LoadingTime wants to solv ...

  2. 【jquery插件】-网页下雪效果

        又到了年底,从圣诞节开始,可以发现各大网站的活动是越来越多,都变的银装素裹,本人由于业务需求也需要做这么一个效果,所以就通过google大神找了一下相关资源,结果就出现了N种雪花效果的方式.种 ...

  3. 让 SpringMVC 接收多个对象的4种方法

    问题背景: 我要在一个表单里同时一次性提交多名乘客的个人信息到SpringMVC,前端HTML和SpringMVC Controller里该如何处理? 第1种方法:表单提交,以字段数组接收: 第2种方 ...

  4. 异步化DAO的设计和实践

    目前,公司技术规划要求未来所有的服务要全面实现异步化接口,使得每个服务能达到1万/秒的单机性能.我们知道,在一个服务请求中,可能会调用其他服务,还会使用memcache.kv以及mysql等.目前,大 ...

  5. SpringMVC学习系列- 表单验证

    本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图上展示WebModel中的数据更加轻松. 一.首先我们先做一个简单了例子来对Spring MV ...

  6. python之路-模块 WebDriver API

    相关文档: http://selenium-python.readthedocs.org/en/latest/api.html#selenium.common.exceptions.InvalidEl ...

  7. [Hapi.js] View engines

    View engines, or template engines, allow you to maintain a clean separation between your presentatio ...

  8. 用ajaxFileUpLoad上传文件不能正确取得返回值的问题

    刚開始没有认为ajax请求的dataType參数的重要性,用了ajaxFileUpLoad插件后,假设页面代码例如以下: fileElementId : ['imageToUpload'], url ...

  9. Linux :: vi E212: Can't open file for writing

    Linux :: vi E212: Can't open file for writing sysct1.conf 可能无写权限!查看方法:ls -lh /etc/sysct1.conf如果没有,则c ...

  10. [CSAPP笔记][第一章计算机系统漫游]

    计算机系统漫游 我们通过追踪hello程序的生命周期来开始对系统的学习—–从它被程序员创建,到系统上运行,输出简单的消息,然后终止.我们沿着这个程序的生命周期,简要介绍一些逐步出现的概念,专业术语和组 ...