如何创建和销毁对象(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. 优先考虑用静态工厂方法代替构造器 优点: - 静态工厂方法相比于构造器,它们有名称 - 不需要每次在使用的时候创建一个对象 - 可以返回原返回 ...
随机推荐
- MySQL加密算法
1.不可逆加密: PASSWORD(),ENCRYPT(,),MD5(),SHA5(). 2.可逆的加密算法: ENCODE(,) DECODE(,):加密解密字符串.该函数有两个参数:被加密或解 ...
- IIS部署网部常用问题汇总
1.unrecognized attribute 'targetframework' A: 需要注册.net framework到iis.步骤如下: (1)'Start' -> 'CMD' (2 ...
- VC学习笔记:对话框
VC学习笔记:对话框 SkySeraph NOV.11st 2009 HQU Email-zgzhaobo@gmail.com QQ-452728574 Latest Modified Date:O ...
- [剑指Offer] 47.求1+2+3+...+n
题目描述 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). [思路]用&&的短路思想来求和 ...
- coreldraw x5提示盗版警告解决方法
CorelDRAW是一款图形图像软件,大多数用户使用的都是coreldraw x5破解版,所以基本上都收到了coreldraw x5提示盗版警告,导致不能用,没关系,绿茶小编有解决方法. coreld ...
- zoj 1298 Domino Effect (最短路径)
Domino Effect Time Limit: 2 Seconds Memory Limit: 65536 KB Did you know that you can use domino ...
- hadoop SequenceFile示例
1.写入,SequenceFile的key和value不一定是Writable,只要能被Serialization序列化和反序列化就可以. private static final String[] ...
- BZOJ2301:[HAOI2011]Problem b——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2301 https://www.luogu.org/problemnew/show/P2522 对于给 ...
- BZOJ1901:Zju2112 Dynamic Rankings——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1901 Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序 ...
- android eclipse ndk使用记录
为方便开发jni程序,android提供了ndk包来简化开发过程,避免开发人员下载完整的平台代码,并且可以在windows环境下集成到eclipse里面,大大加快了开发速度.这里记录下一个简单例子. ...