目录
第1条:考虑使用静态工厂方法代替构造器
第2条:遇到多个构造器参数时考虑用构建器
第3条:用私有构造器或者枚举类型强化Singleton属性
第4条:通过私有构造器强化不可实例化的能力
第5条:避免创建不必要的对象
第6条:消除过期的对象引用
第7条:避免使用终结方法

第2章 创建和销毁对象

第1条:考虑使用静态工厂方法代替构造器

通过使用静态工厂方法而不是使用构造器来创建类。

举例:Boolean.valueOf(boolean)方法,将boolean转换为Boolean对象引用。

有以下优势:

1)静态工厂方法有名称,可以表示方法的意思

2)不必在每次调用的时候都创建新对象(对象缓存能力)。

不可变类可预先构建实例,缓存起来重复使用。

3)可以返回原返回类型的任何子类型的对象

4)在创建参数化类型的时候代码更简洁。

//我们平时创建list
List<String> list = new Arraylist<>();
//使用google 工具类
List<String> list = Lists.newArrayList();
静态工厂方法常用名称:

valueOf、of、getInstance、newInstance、getType、newType(如newArrayList)

第2条:遇到多个构造器参数时考虑用构建器

当有很多个构造参数,且有几个参数是可选的,考虑使用Builder

public class NutritionFacts {
/**
必填参数
*/
private final int servingSize;
private final int servings;
/**
可选参数
*/
private final int fat;
private final int sodium;
public static class Builder {
private final int servingSize;
private final int servings;
private int fat = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder fat(int fat) {
this.fat = fat;
return this;
}
public Builder sodium(int sodium) {
this.sodium = sodium;
return this;
}
public P build() {
return new P(this);
}
}
private NutritionFacts(Builder builder) {
this.servingSize = builder.servingSize;
this.servings = builder.servings;
this.fat = builder.fat;
this.modium = builder.modium;
}
}

客户端代码

NutritionFacts p = new NutritionFacts.Builder(200, 8).fat(100).sodium(35).build();

更高级使用:

public interface Builder<T> {
public T build();
}
public static class NutritionFacts.Builder implements Builder<P>

这样可以将Builder<NutritionFacts>传给方法,并结合抽象工厂创建NutritionFacts实例。

第3条:用私有构造器或者枚举类型强化Singleton属性

举例1:使用私有构造器

public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {} //私有构造器
//other code
}

为了保证Singleton类是可序列化的

1)声明加上implents Serializable

2) 所有实例域都是transient

3)提供一个readResolve方法

private Object readResolve() {
return INSTANCE;
}

举例2:使用枚举

public enum Singleton {
INSTANCE;
}

第4条:通过私有构造器强化不可实例化的能力

主要用于在写工具类的时候。

public class XXXUtils {

private XXXXUtils() {
}
//other code
}

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

当你应该重用现有对象的时候,不要创建新的对象。

举例1:

m方法会被频繁调用时,会创建n多的String实例。

public String m() {
String s = new String("str");
//other code
}

改进后,m方法被频繁调用,但是s会被复用。

public String m() {
String s = "str";
}

举例2:

求所有Integer的和,因声明为Long sum,而不是long sum,程序将创建约2的31次方个Long实例。

public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++)
{
sum += i; //这里每次都会创建一个Long实例。要当心无意识的自动装箱。
}
System.out.println(sum);
}

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

主要讲了内存泄露问题。

举例1:类自己管理内存,易导致内存泄露。

下面是简单的栈实现,程序每次测试都会通过,但是有个隐藏问题——”内存泄露“。

栈先增长,再收缩,栈中弹出的对象不会被当做垃圾回收,即使使用栈的程序不再引用这些对象。

public class Stack {
private Object[] elements;
private int size;
private static final int DEFAULT_INIT_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INIT_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;
}
}

为何会出现内部泄露?

Stack通过数组保存数组元素,相当于自己管理内存。只要是类自己管理内存,就应该警惕内存泄露问题。

举例2:内存泄露的另一个常见来源是缓存

缓存内存泄露:把对象引用放到缓存中,容易被遗忘,不再有用之后仍留在缓存中。

情形1:只要在缓存外有对某个项的键的引用,该项就有意义。

解决方法:使用WeakHashMap。

(记住只有当缓存项生命周期由该键的外部引用而不是值决定时,WeakHashMap才有意义)

情形2:缓存项生命周期是否有意义,不是很容易确定

解决方法:后台线程定期清理 or 缓存添加新条目时顺便清理(LinkedHashMap.removeEldestEntry()方法)

情形3:更复杂的缓存

解决方法:使用java.lang.ref

举例3:内存泄露的第三个常见来源是监听器和其他回调

比如注册回调,但是没有显式地取消回调。解决方法:保存它们的弱引用(weak ref),如只将它们保存为WeakHashMap的键。

第7条:避免使用终结方法

终结方法就是finalize()方法。

Java语言规范不保证终结方法会被及时地执行,更不保证一定会被执行。

System.gc()增加了终结方法被执行的机会,但不保证一定会被执行。

《Effective Java 2nd》第2章 创建和销毁对象的更多相关文章

  1. [Effective Java 读书笔记] 第二章 创建和销毁对象 第一条

    第二章  创建和销毁对象 第一条 使用静态工厂方法替代构造器,原因: 静态工厂方法可以有不同的名字,也就是说,构造器只能通过参数的不同来区分不同的目的,静态工厂在名字上就能表达不同的目的 静态工厂方法 ...

  2. [Effective Java读书笔记] 第二章 创建和销毁对象(1~7)

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3537576.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  3. 《Effective Java》第1章 创建和销毁对象

    第1条 用静态工厂方法代替构造器 这个静态工厂,与设计模式中的静态工厂不同,这里的静态工厂方法,替换为“静态方法”比较好理解,主要就是建议编写静态方法来创建对象. 使用静态方法的好处: 1.静态方法有 ...

  4. [Effective Java 读书笔记] 第二章 创建和销毁对象 第六-七条

    第六条 消除过期引用 JAVA中依然会有 memory leak的,比如一个栈先增长再收缩,那么从栈中弹出的对象是不会被当做垃圾回收的,即时使用栈的程序不再引用这些对象.这是因为栈的内部维护着对这些对 ...

  5. [Effective Java 读书笔记] 第二章 创建和销毁对象 第五条

    第五条 避免创建不必要的对象 书中一开始举例: String s = new String("stringette"); // don't do this //应该使用下面,只会创 ...

  6. [Effective Java 读书笔记] 第二章 创建和销毁对象 第三 四条

    第三条 用私有构造器或者枚举类型强化singleton属性 singleton指只能被实例化一次的类,即将构造器设置为私有,使用公有静态成员来实例化,且只实例化一次对象 第四条 通过私有构造器强化不可 ...

  7. [Effective Java 读书笔记] 第二章 创建和销毁对象 第二条

    第二条 遇到多个构造器参数时,可以考虑用构建器 当遇到有多个构造器参数时,常见的是用重叠构造器,即: public class TestClass{ public TestClass(int para ...

  8. 《Effective Java》第2章 创建和销毁对象

    第2条:遇到多个构造器参数时要考虑用构建器 与构造器相比,builder的微略优势在于,builder可以有多个可变(varargs)参数.构造器就像方法一样,只能有一个可变参数.因为builder利 ...

  9. 《Effective Java》读书笔记 - 2.创建和销毁对象

    Chapter 2 Creating and Destroying Objects item 1:Consider static factory methods instead of construc ...

随机推荐

  1. 【linux系列】vi模式下查找和替换

    一.查找 1.查找命令 /pattern<Enter> :向下查找pattern匹配字符串 ?pattern<Enter> :向上查找匹配字符串 在使用了查找命令之后,使用如下 ...

  2. IT公司常见的内网漏洞表格

    访问控制类漏洞与隐患 这一类漏洞与隐患属于访问控制与身份鉴别问题,一般有没有配置访问控制.访问控制弱(弱口令或者空口令),身份鉴别可以绕过等问题 漏洞协议组件 漏洞类型 漏洞评级 SSH 弱口令 严重 ...

  3. jhipser微服务架构介绍

    内容提要 本文涉及以下内容: 微服务架构介绍 spring cloud介绍 jhipster架构介绍 微服务架构介绍 微服务概念 微服务和SOA很相似,都是按照业务功能把系统拆分成一个一个的服务.比如 ...

  4. Testlink在CentOS、windows安装

    有幸在CentOS\windows上都安装过Teslink程序,总结一下.如下: 一.CentOS安装: 1.安装包需要: xampp xampp-linux-x64-5.6.3-0-installe ...

  5. 树形DP求各点能走到的最远距离

    hdu2196 Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. 微信开发(2):微信js sdk分享朋友圈,朋友,获取config接口注入权限验证(转)

    进行微信开发已经一阵子了,从最初的什么也不懂,到微信授权登录,分享,更改底部菜单,素材管理,等. 今天记录一下微信jssdk 的分享给朋友的功能,获取config接口注入. 官方文档走一下简单说:四步 ...

  7. 01.MyBatis入门

        MyBatis入参考文档:http://mybatis.org/mybatis-3/zh/  1.使用MyBatis前的准备 1.增加Maven依赖 <dependency> &l ...

  8. MVC之路由

    1.路由规则理解: 在MVC项目中,路由是一个独立的模块,需要引入System.Web.Routing ,路由的作用就是确定控制器和行为,同时确定其他的参数,然后将这些信息传递个相应的控制器和行为. ...

  9. Python开发【数据结构】:算法(二)

    堆排序 1.—树与二叉树简介 树是一种数据结构 比如:目录结构 树是一种可以递归定义的数据结构 树是由n个节点组成的集合: 如果n=0,那这是一棵空树: 如果n>0,那存在1个节点作为树的根节点 ...

  10. Nginx 使用总结

    一.使用 nginx 实现 灰度发布 灰度发布,现在是很多大项目的一个标配运维特性,我们可以将一个“新的版本代码”发布到集群中的少数几台(组)机器上,以便引入线上少量真实用 户进行测试,用于验证产品改 ...