《Effective Java》笔记 :(一)创建和销毁对象
一 .考虑用静态工厂方法代替构造器
1. 静态工厂方法与设计模式中的工厂方法模式不同,注意不要混淆
例子:
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
2. 采用静态工厂方法比构造器方法的优势
①有名称
② 不必在每次调用他们的时候都创建一个新的对象
③可以返回原类型的任何子类型的对象
④在创建参数化实例的时候,使代码更加简洁
比如
Map<String,List<String>> m = new HashMap<String,List<String>>();
当参数越多的时候会越复杂,可以考虑用静态工厂方法
public static<K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
Map<String,List<String>> m = HashMap.newInstance();
3.采用静态工厂方法的缺点:类如果不含公有的或者受保护的构造器,就不能被子类化;与其他的静态方法实质上没区别
静态工厂方法惯用名词:valueOf/of/getInstance/newInstance/getType/newType
二.遇到多个构造器参数时考虑用构建器(建造器Builder)
重构构造器模式可行,但是参数很多的时候,客户端代码很难编写,容易出错,且较难阅读维护
替代办法一: 使用JavaBeans模式,调用无参构造器创建对象,然后调用setter设置参数
public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
private int servings = -1; // " " " "
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0; public NutritionFacts() {
} // Setters
public void setServingSize(int val) {
servingSize = val;
} public void setServings(int val) {
servings = val;
} public void setCalories(int val) {
calories = val;
} public void setFat(int val) {
fat = val;
} public void setSodium(int val) {
sodium = val;
} public void setCarbohydrate(int val) {
carbohydrate = val;
} public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
}
}
这种办法有缺陷:① 构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态 ②JavaBeans模式阻止了把类做成不可变的可能
替代办法二:使用Builder模式
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate; public static class Builder {
// Required parameters
private final int servingSize;
private final int servings; // Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0; public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
} public Builder calories(int val) {
calories = val;
return this;
} public Builder fat(int val) {
fat = val;
return this;
} public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
} public Builder sodium(int val) {
sodium = val;
return this;
} public NutritionFacts build() {
return new NutritionFacts(this);
}
} private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
} public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();
}
}
三.用私有构造器或者枚举类型强化Singleton属性
单元素的枚举类型已经成为实现Singleton的最佳方法
public enum Elvis {
INSTANCE; public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
} // This code would normally appear outside the class!
public static void main(String[] args) {
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
}
}
四.通过私有构造器强化不可实例化的能力
企图通过将类做成抽象类来强制该类不可实例化,是行不通的 --可以子类化,子类可以实例化
让这个类包含私有构造器,就不能实例化了
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
}
五.避免创建不必要的对象
String s = new String("hello")------->两个实例
换成
String s = "hello"; ------> 一个实例
优先使用静态工厂方法,而不是构造器,避免创建不必要的对象
public class Person {
private final Date birthDate; public Person(Date birthDate) {
// Defensive copy - see Item 39
this.birthDate = new Date(birthDate.getTime());
} // Other fields, methods omitted // DON'T DO THIS!
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
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;
}
} //上面的程序每次被调用都会创建Date ,Calendar,TimeZone没必要
//下面的程序使用了一个静态初始化器,避免了效率低下 class Person {
private final Date birthDate; public Person(Date birthDate) {
// Defensive copy - see Item 39
this.birthDate = new Date(birthDate.getTime());
} // Other fields, methods /**
* The starting and ending dates of the baby boom.
*/
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;
}
}
优先使用基本类型而不是装箱基本类型,当心无意识的自动装箱
//声明成Long而不是long,意味着构造了很多Long实例。应该改成long
public class Sum {
// Hideously slow program! Can you spot the object creation?
public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
}
六.消除过期的对象引用
//下面的例子存在着内存泄漏的可能,因为过期引用并没有被回收
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();
return elements[--size];
} /**
* Ensure space for at least one more element, roughly doubling the capacity
* each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
} //修复方法
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
return result;
}
内存泄漏的另一个常见来源是缓存,处理方法是使用WeakHashMap代表缓存
内存泄漏的第三个常见来源是监听器和其他回调,,处理办法是保存他们的弱引用,例如只将它们保存成WeakHashMap中的键
七.避免使用终结方法
而使用显式终止方法,比如InputStream/OutputStream和java.sql.Connection上的close()方法。
通常与try-finally结合使用,在finally子句中调用显式终止方法。
《Effective Java》笔记 :(一)创建和销毁对象的更多相关文章
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- [Effective Java]第二章 创建和销毁对象
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 《Effect Java》学习笔记1———创建和销毁对象
第二章 创建和销毁对象 1.考虑用静态工厂方法代替构造器 四大优势: i. 有名称 ii. 不必在每次调用它们的时候都创建一个新的对象: iii. 可以返回原返回类型的任何子类型的对象: JDBC ...
- 《Effective Java》读书笔记 - 2.创建和销毁对象
Chapter 2 Creating and Destroying Objects item 1:Consider static factory methods instead of construc ...
- 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器
类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...
- 【Java基础】创建和销毁对象
Num1:考虑用静态工厂方法代替构造器 对于类而言,常见的方法是提供一个公有的构造器,但其实还有一种方法叫做静态工厂方法(static factory method),它只是一个返回类的实例静态方法. ...
- Effective Java 读书笔记之一 创建和销毁对象
一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...
- Effective Java 学习笔记之创建和销毁对象
一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法 ...
- 《Effective Java》读书笔记(一)之创建和销毁对象
最近在研读<Effective Java>一书,读书不做点笔记,感觉很容易就忘掉,于是用本篇博客来记录阅读此书的笔记. 郑重声明: 由于是<Effective Java>一书的 ...
- Effective Java学习笔记--创建和销毁对象
创建和销毁对象 一.静态工厂方法代替构造器 静态工厂方法的优缺点 优点: 1.可以自定义名称(可以将功能表述的更加清晰) 2.不必每次调用都创建新的对象(同一对象重复使用) 3.返回的类型可以是原返回 ...
随机推荐
- Brackets安装angularjs插件
Brackets是Adobe公司研发的一款开源WEB前端开发框架,界面清爽简约,代码提示功能比较强大,而且支持第三方插件,其提供的插件库中有大量的对Brackets感兴趣的开发人员所开发的插件,使用者 ...
- ArcServer10.1系列产品之ArcGIS Web Adaptor (IIS)
1.关于 ArcGIS Web Adaptor 通过 ArcGIS Web Adaptor,可以将 ArcGIS for Server 与您现有的 Web 服务器进行集成.ArcGIS Web Ada ...
- 【虚拟机-磁盘管理】理解及快速测定 Azure 虚拟机的磁盘性能
随着越来越多的用户将生产系统迁移到 Azure 平台的虚拟机服务中,Azure 虚拟机的性能愈发被关注.传统的数据中心中,我们通常使用 CPU,内存,存储和网络的性能来衡量生产压力.特别是对于 IO ...
- Spring.Net 能为我们做点什么
本文内容 概述 背景 模块 使用场景 入门应用 Spring.NET 相关项目 本文正式开始前,我以目前所能想到的.此时此刻能想到的,先简单说下,为什么会有像 Spring.Net 这样的东西.首先, ...
- pc端常见布局---水平居中布局 单元素定宽
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- HTTP协议初探
HTTP协议初探 HTTP协议初探 什么是http协议? 遵守协议的双方 再来回答什么是http协议 抓到这两段文本 可以总结出以下规律 HTTP 请求命令(动作,谓词 ,METHOD) GET 和 ...
- 字符串转换JSON 的方法
function (sJSON) { if (window.JSON) { return window.JSON.parse(sJSON); } else { return eval('(' + sJ ...
- UVA11212 EditingaBook ( IDA*搜索)
首先说说IDS,就DFS限定一个层数上限maxd,如果在maxd范围内没有找到解,就增加maxd,继续搜索. 当访问到当前结点u时,估计还要搜索h(u)层,如果h(u)+当前层数d>maxd的时 ...
- LeetCode分类-前400题
1. Array 基础 27 Remove Element 26 Remove Duplicates from Sorted Array 80 Remove Duplicates from Sorte ...
- FastText算法
转载自: https://www.cnblogs.com/huangyc/p/9768872.html 0. 目录 1. 前言 2. FastText原理 2.1 模型架构 2.2 层次SoftMax ...