如何创建和销毁对象(Effective Java 第二章)
最近有在看Effective Java,特此记录下自己所体会到的东西,写篇博文会更加的加深印象,如有理解有误的地方,希望不吝赐教。
这章主题主要是介绍:何时以及如何创建对象,何时以及如何避免创建对象,如何确保他们能够适时的销毁,以及如何管理对象销毁之前必须进行的清理动作。下面我会根据书中内容+例子总结:
一、考虑用静态工厂方法代替构造器(体现了如何创建对象、避免创建对象)
如何获取一个类的实例,最常用的方法就是提供一个共有的构造器, 但是还有一种方法就是使用静态工厂方法(与设计模式中的工厂方法不同)。静态工厂方法只是一个静态的,用来返回当前类型或子类型的实例的方法。
先来说说静态工厂方法与构造器不同的优势,然后我们在根据例子来体现:
优势:1、静态工厂方法可以有自己的名称。这样更容易理解当前方法所要表达的意思。
以随机生成数类为案例,看第二个构造方法(构造一个指定最小值到Integer.MAX_VALUE的区间)和第三个构造方法(构造一个Integer.MIN_VALUE到指定max的区间),两者表达的意思完全不同,且存在是有意义的, 但是如果这两者同时存在将会出现编译错误:Duplicate method RandomIntGenerate(int) in type RandomIntGenerate;问题原因是出现了两个签名相同的(返回值、名称、参数类型及个数均相同)方法。
/**
* @Description: 随机生成数 以构造器方法为例
* @author yuanfy
* @date 2017年7月7日 上午9:26:04
*/
public class RandomIntGenerate {
//定义最小值
private int min;
//定义最大值
private int max;
/**
* 使用构造器生成指定区间的随机数
* @param min
* @param max
*/
public RandomIntGenerate(int min, int max) {
this.min = min;
this.max = max;
}
/**
* 指定最小值到Integer.maxValue区间的构造器
* @param min
*/
public RandomIntGenerate(int min) {
this.min = min;
this.max = Integer.MAX_VALUE;
} /**
* 指定最大值到Integer.minValue区间的构造器 如果添加了这个方法,将会引起第二个和第三个构造方法的编译错误。
* @param min
*/
public RandomIntGenerate(int max) {
this.min = Integer.MIN_VALUE;
this.max = max;
}
}
通过上面看出用构造方法时候会造成方法歧义,下面我们通过静态工厂方法来创建对象实例就会清楚很多。
/**
* @Description: 随机生成数 以静态工厂方法为例
* @author yuanfy
* @date 2017年7月7日 上午9:26:04
*/
public class RandomIntGenerate {
//定义最小值
private int min;
//定义最大值
private int max;
/**
* 使用构造器生成指定区间的随机数 (不对外开放)
* @param min
* @param max
*/
private RandomIntGenerate(int min, int max) {
this.min = min;
this.max = max;
}
/**
* @Description: 使用静态工厂方法 创建指定两端边界值的构造器
* @param min 最小值
* @param max 最大值
* @return RandomIntGenerate对象
* @author yuanfy
* @date 2017年7月7日 上午9:56:37
*/
public static RandomIntGenerate between(int min, int max) {
return new RandomIntGenerate(min, max);
} /**
* @Description: 使用静态工厂方法 创建大于指定最小值边界的构造器
* @param min 最小值
* @return RandomIntGenerate对象
* @author yuanfy
* @date 2017年7月7日 上午9:56:37
*/
public static RandomIntGenerate biggerThanMin(int min) {
return new RandomIntGenerate(min, Integer.MAX_VALUE);
} /**
* @Description: 使用静态工厂方法 创建小于最大值边界的构造器
* @param max 最大值
* @return RandomIntGenerate对象
* @author yuanfy
* @date 2017年7月7日 上午9:56:37
*/
public static RandomIntGenerate smallerThanMax(int max) {
return new RandomIntGenerate(Integer.MIN_VALUE, max);
}
}
使用场景:当一个类需要多个带有相同签名的构造器时,就可以用静态工厂方法代替构造器。
2、不必每次调用他们的时候都创建一个新对象。例如Boolean.valueOf()方法。下面是截取java.lang.Boolean类源码中的代码,这个静态方法返回均为不可变Boolean对象TRUE或者FALSE。
public final class Boolean implements java.io.Serializable,
Comparable<Boolean>
{
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true); /**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false); public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
}
除了这个例子,还有我们常见的单例模式(饿汉式)。
public class SingletonModeDemo { private static SingletonModeDemo demo = new SingletonModeDemo(); /**
* @Description: 单例模式(饿汉式)
* @author yuanfy
* @date 2017年7月7日 上午10:43:47
*/
public static SingletonModeDemo newInstance(){
return demo;
}
}
3、可以返回原返回类型的任何子类型对象。其实这就跟多态有关了,下面以动物类为例。
//动物类
class Animal{
//动物都有名字
private String name; public Animal(String name) {
this.name = name;
} }
//鸟类
class Bird extends Animal { public Bird(String name) {
super(name);
}
}
//大小类
class Elephant extends Animal { public Elephant(String name) {
super(name);
}
}
//动物集合类
public class Animals {
private Animals(){} public static Animal getDog(String name) {
return new Bird(name);//事实证明可以返回动物类的任何子类
} public static Animal getPig(String name) {
return new Elephant(name);//事实证明可以返回动物类的任何子类
}
}
4、在创建参数化类型实例的时候,它们使代码变得更加简单。以书中举的HashMap为例。
创建HashMap实例时,不管参数有多少都必须指明,这就增加了代码量了。如下代码:
Map<String, List<String>> map = new HashMap<String, List<String>>();
如果使用静态工厂方法创建实例则会简化很多。如下代码:
public class HashMapUtil { /**
* @Description: 使用静态工厂简化参数
* @author yuanfy
* @date 2017年7月7日 上午11:14:34
*/
public static <K, V> HashMap<K, V> newInstance(){
return new HashMap<K, V>();
} public static void main(String[] args) {
Map<String, List<String>> map = HashMapUtil.newInstance();
}
}
劣势:使用静态方法的类如果不含有共有的或受保护的构造器,就不能被子类化。
第二个就是与其他的静态方法没什么区别。所以在静态方法命名上要注意使用,通常用惯用名称。
- valueOf - 返回的实例与它的参数具有相同的值,一般作为类型转换使用,例如
Boolean.valueOf(boolean)
- of - valueOf的更为简洁的替代。
- getInstance - 返回的实例通过方法的参数来描述,但不能说与参数具有同样的值。对于Singleton来说,使用无参getInstance,返回唯一的实例。
- newInstance - 像getInstance一样,但其能够确保每次都返回新的对象。
- getType - 像getInstance一样,但是在工厂方法处于不同的类中的时候使用,返回对象类型
- newType - 像newInstance 一样,但是在工厂方法处于不同的类中的时候使用,返回对象类型
二、遇到多个构造器参数时要考虑用构建器(体现了如何创建对象)
书中NutritionFacts例子已经说明的很详细了,请参考书中例子。
三、用私有构造器或者枚举类型强化Singleton属性
第一种使用私有构造器来强化Singleton属性,就是单例模式中的饿汉式是典型的例子;
第二种用枚举类型来强化Singleton属性,确实实用。其中书中说道“单元素的枚举类型已经成为实现Singleton的最佳方法”
/**
* @Description: 用枚举来实现单例模式
* @author yuanfy
* @date 2017年7月7日 下午2:30:16
*/
public enum EnumDemo {
INSTANCE;//调用这个就已经调用了EnumDemo()构造方法。
private Date instance; private EnumDemo() {
instance = new Date();
} public Date getInstance(){
return instance;
} public static void main(String[] args) {
System.out.println(EnumDemo.INSTANCE.getInstance());
}
}
四、通过私有构造器强化不可实例化的能力。
从上面那个单例模式的例子来看是严谨的(在缺少显示构造器的情况下,编译器会自动提供一个共有的、无参的缺省构造器),因为没有私有化构造器,所以直接new SingletonModeDemo()就可以创建实例对象了。 强化后的代码:
public class SingletonModeDemo { private static SingletonModeDemo demo = new SingletonModeDemo(); /**
* 私有化构造器,使其获取实例的入口只有newInstance()方法
*/
private SingletonModeDemo(){} /**
* @Description: 单例模式(饿汉式)
* @author yuanfy
* @date 2017年7月7日 上午10:43:47
*/
public static SingletonModeDemo newInstance(){
return demo;
}
}
五、避免创建不必要的对象
主要思想是:最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。如果对象是不可变的,它始终可以被重用。
前面几点也介绍了相关的案例,如使用静态工厂方法可以适当表面创建不必要的对象。单例模式也是一样。所以在编程的时候多多注意下就行,写出好的代码这方面也是一种体现。
六、消除过期的对象引用
七、避免使用终结方法
后面两点没有什么更深的理解,所以还得多看几遍书。
如何创建和销毁对象(Effective Java 第二章)的更多相关文章
- [Effective Java]第二章 创建和销毁对象
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 对于所有对象都通用方法的解读(Effective Java 第二章)
这篇博文主要介绍覆盖Object中的方法要注意的事项以及Comparable.compareTo()方法. 一.谨慎覆盖equals()方法 其实平时很少要用到覆盖equals方法的情况,没有什么特殊 ...
- [Effective Java 读书笔记] 第二章 创建和销毁对象 第一条
第二章 创建和销毁对象 第一条 使用静态工厂方法替代构造器,原因: 静态工厂方法可以有不同的名字,也就是说,构造器只能通过参数的不同来区分不同的目的,静态工厂在名字上就能表达不同的目的 静态工厂方法 ...
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- effective java读书小记(一)创建和销毁对象
序言 <effective java>可谓是java学习者心中的一本绝对不能不拜读的好书,她对于目标读者(有一点编程基础和开发经验)的人来说,由浅入深,言简意赅.每一章节都分为若干的条目, ...
- 和我一起学Effective Java之创建和销毁对象
前言 主要学习创建和销毁对象: 1.何时以及如何创建对象 2.何时以及如何避免创建对象 3.如何确保它们能够适时地销毁 4.如何管理对象销毁之前必须进行的清理动作 正文 一.用静态工厂方法代替构造器 ...
- 《Effective Java》读书笔记(一)之创建和销毁对象
最近在研读<Effective Java>一书,读书不做点笔记,感觉很容易就忘掉,于是用本篇博客来记录阅读此书的笔记. 郑重声明: 由于是<Effective Java>一书的 ...
- Effective Java(1)-创建和销毁对象
Effective Java(1)-创建和销毁对象
- [Effective Java] 创建和销毁对象篇
[Effective Java] 创建和销毁对象篇 1. 优先考虑用静态工厂方法代替构造器 优点: - 静态工厂方法相比于构造器,它们有名称 - 不需要每次在使用的时候创建一个对象 - 可以返回原返回 ...
随机推荐
- 在linux下如何显示隐藏文件
#显示所有文件(包含隐藏文件)ls -a #只显示隐藏文件l.或者ls -d .* #在XWindow的KDE桌面中在"查看(View)"菜单里选"显示隐藏文件(Show ...
- Microsoft Edge goes Chromium
Microsoft Edge goes Chromium https://techcrunch.com/2018/12/06/microsoft-edge-goes-chromium-and-maco ...
- 【Python】Python 新式类介绍
本文转载自:kaka_ace's blog 我们使用 Python 开发时, 会遇到 class A 和 class A(object) 的写法, 这在 Python2 里是有概念上和功能上的区别, ...
- JQuery UI的拖拽功能实现方法小结
JQuery UI提供的API极大简化了拖拽功能的开发.只需要分别在拖拽源(source)和目标(target)上调用draggable和droppable两个函数即可. 拖拽原理 首先要明确几个概念 ...
- vscode Variables Reference
vscode Variables Reference 您可以在以下链接中找到该列表:https://code.visualstudio.com/docs/editor/variables-refere ...
- [BZOJ4822] [CQOI2017] 老C的任务
题目链接 BZOJ:https://lydsy.com/JudgeOnline/problem.php?id=4822. 洛谷:https://www.luogu.org/problemnew/sho ...
- MHA选择主库源码解析
知数堂第5期MySQL实战班学员,第10期MySQL优化班学员,现任职助教. MHA在选择新的主库之前,会先把活着的slave分为几个数组,分别为latest(最靠前的slave数组),pref(优先 ...
- POJ2891:Strange Way to Express Integers——题解
http://poj.org/problem?id=2891 题目大意: k个不同的正整数a1,a2,...,ak.对于一些非负m,满足除以每个ai(1≤i≤k)得到余数ri.求出最小的m. 输入和输 ...
- BZOJ4539 [Hnoi2016]树 【倍增 + 主席树】
题目链接 BZOJ4539 题解 我们把每次复制出来的树看做一个点,那么大树实际上也就是一棵\(O(M)\)个点的树 所以我们只需求两遍树上距离: 大树上求距离,进入同一个点后在模板树上再求一次距离 ...
- React setState和修改props触发的钩子
1. setState的改变会触发4个生命周期钩子 shouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate 2. props的 ...