Effective java笔记2--创建于销毁对象
一、创建对象的两种方式
1、提供公有的构造器。
2、提供一个返回类实例的静态方法。
二、使用静态方法创建对象
优势:
1、静态工厂方法的一个好处是,与构造函数不同,静态工厂方法具有名字。产生的客户端代码更易于阅读。
//例如,构造函数BigInteger(int,int,Random)返回的BigInteger可能是素数,
BigInteger.probalePrime()的静态工厂方法,表达显然更为清楚
2、静态工厂方法的第二个好处,与构造函数不同,它们每次被调用的时候,不要求非得创建一个新的对象。对于不可变类,可以预先使用构建好的实例,或将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象。
3、静态方法可以返回原返回类型的任何子类型的对象,这对于基于接口的框架提供了更大的灵活性。
4、静态方法在创建参数化类型实例的时候,可以使代码变得更加简洁。
缺点:
1、类如果不含公有的或受保护的构造器,就不能被子类化。有时这正好是优势,复合比继承更高效。
2、用于创建对象静态方法的静态方法实际上与其他静态方法没有任何区别,所以除非文档有详细的描述,否则很难找到如何实例化通过这种方法创建的类对象。
最佳实践:
1、当一个类需要多个带有相同签名的构造器时,就用静态工厂方法代替构造器,并且慎重地选择名称以便突出它们之间的区别。
2、要求客户端通过接口来引用被返回的对象,而不是通过它的实现类,即返回类型为接口而不是实现类。
3、使用惯用名称来命名静态工厂方法:
valueOf:不太严格的讲,该方法返回的实例与它的参数具有相同的值,这样的静态工厂方法实际上是类型转换方法。
of:valueOf的一种更为简洁的替代,在EnumSet中使用并流行起来。
getInstance:返回的实例是通过方法的参数来描述的,但是不能够说与参数具有同样的值。对于Singleton来说,该方法没有参数,且返回唯一的实例。
newInstance:像getInstance一样,但newInstance能够确保返回的每个实例都与其他所有实例不同。
getType:像getInstance一样,但在工厂方法处于不同的类中时使用。Type表示工厂方法所返回的对象类型。
newType:像newInstance一样,但在工厂方法处于不同的类中时使用。Type表示工厂方法所返回的对象类型。
三、避免创建重复的对象
重复使用同一个对象,而不是每次需要的时候就创建一个功能上等价的新对象,通常前者更为合适。重用方法既快速,也更为流行。如果一个对象时非可变的(immutable),那么它总是可以被重用。
String s = new String("silly"); //DON'T DO THIS!
上面的实参"silly"本身就是一个String实例,功能上等同于所有被构造函数创建的对象,如果这种用法放在一个循环或者一个被频繁调用的方法中,那么成千上万的String实例会被创建出来。
改进版本如下:
String s = "No longer silly";
这个版本只是用一个String实例,可以保证对于所有在同一个虚拟机中运行的代码,只要他们包含相同的字符串字面常量,则该对象就会被重用。
不要错误地认为本条目所介绍的内容暗示”创建对象的代价是非常昂贵的,我们应该要尽可能地避免创建对象“。相反,由于小对象的构造函数只做很少量的工作,所以,小对象的创建和回收动作非常廉价的,特别是在现代的JVM实现上更是如此,通过创建附加的对象,以使得一个程序更加清晰、简洁、功能强大,这往往也是一件好事。
反之,通过维护自己的对象池(object pool)来避免对象的创建工作并不是一个号的做法,除非池中的对象时非常重量级的。一个正确使用对象池的典型例子就是数据库连接池。建立数据库连接的代价非常昂贵的,因此重用这样的对象非常有意义。
四、清除过期的对象引用
由于java是支持垃圾回收的语言,内存泄露是很隐蔽的,举个例子:
//Can you spot the "memory leak"?
public class Stack{
private Object[] elements;
private int size = 0; public Stack(int initialCapacity){
this.elements = new Object[initalCapacity];
} public void push(Object e){
ensureCapacity();
elements[size++] = e;
} public Object pop(){
if(size==0)
throw new EmptyStackException();
return elements[--size];
} private void ensureCapacity(){
if(elements.length==size){
Object[] oldElements = elements;
elements = new Object[2*elements.length+1];
System.arraycopy(oldElements,0,elements,0,size); }
}
}
上面的程序中潜伏着一个问题,不严格地讲,这个程序有一个”内存泄露“,随着垃圾回收器活动的增加,或者出于不断增加的内存占用,程序性能的降低会逐渐表现出来。如果栈先是增长,然后再收缩,那么,从栈弹出的对象将不会被当垃圾回收,即使使用栈的客户程序不再引用这些对象,它们也不会被回收。这是因为,栈内部维护着对这些对象的过期引用(absolete reference)。所谓过期引用,是指永远也不会被解除的引用。在本例中,凡是在elements数组的”活动区域(active protion“之外的引用都是过期的,elements的活动区域是指下标小于size的那一部分。
如果一个对象引用被无意识地保留起来了,那么,垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象引用的所有其他对象,即使只有少量的几个对象引用被无意识地保存下来,也会有很多的对象被排除在垃圾回收机制之外,从而对性能造成潜在的重大影响。
对本案例修复方法:
pubic Object pop(){
if(size==0) throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; //Eliminate obsolete reference
return result;
}
清除过期引用的另外一个好处是,如果他们在以后被错误地解除引用,则程序会立即抛出NullPointerException异常,而不是悄悄地错误地运行下去。尽可能早的检测出程序中的错误总是有益的。
Effective java笔记2--创建于销毁对象的更多相关文章
- 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.返回的类型可以是原返回 ...
随机推荐
- Java中的条件运算符
条件运算符( ? : )也称为 “三元运算符”. 语法形式:布尔表达式 ? 表达式1 :表达式2 运算过程:如果布尔表达式的值为 true ,则返回 表达式1 的值,否则返回 表达式2 的值 例如: ...
- Spark- 使用第三方依赖解析IP地址
使用 github上已有的开源项目1)git clone https://github.com/wzhe06/ipdatabase.git 2)编译下载的项目: mvn clean package- ...
- 虚拟主机(多站点配置)的实现--centos上的实现
Apache中配置多主机多站点,可以通过两种方式实现 将同一个域名的不同端口映射到不同的站点(虚拟主机) 将同一个端口映射成不同的域名,不同的域名映射到不同的站点 两种方法可以同时存在,局域网通过 ...
- DP问题如何确定状态
DP问题如何确定状态 一.dp实质 动态规划的实质就是通过小规模的同类型的问题来解决题目的问题. 所以有一个dp数组来储存所有小规模问题的解. 所以确定状态也就是缩小问题规模. 我们求解问题的一般规律 ...
- 【spark】持久化
Spark RDD 是惰性求值的. 如果简单地对RDD 调用行动操作,Spark 每次都会重算RDD 以及它的所有依赖.这在迭代算法中消耗格外大. 换句话来说就是 当DAG图遇到转化操作的时候是不求值 ...
- 慕课网:4-2—— 使用DB facade实现CURD (09:11)
public function test1() { //新增数据: /* $bool=DB::insert('insert into student(name,age) VALUES (?,?)', ...
- Struts05---动态查询
01.在上面案例的login.jsp页面新增 <%-- 2.动态方法的调用 前提是在 struts.xml文件中开启 不推荐! --%> <a href="user/use ...
- 条款24:如果所有的参数都需要类型转换,那么请为此采用non-member函数
首先还是下面这个class; class Rational{ public: Rational(, ); int numurator() const; int denominator() const; ...
- LeetCode OJ:Count Primes(质数计数)
Count the number of prime numbers less than a non-negative number, n. 计算小于n的质数的个数,当然就要用到大名鼎鼎的筛法了,代码如 ...
- flash代码
Flash常用的动作命令一.Flash中的常用命令:1.在当前帧停止播放 on(release){ stop();} 2.从当前帧开始播放 on(release){ play();} 3.跳到第 10 ...