创建和销毁对象
考虑用静态工厂方法代替构造器
对于类而言,为了让客户端获取他自身的一个实例,最常用的方法就是提供一个公有的构造器.
还有一种方法,类可以提供一个公有的静态工厂方法,他只是一个返回类的实例的静态方法.
public static Boolean valueof(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
静态工厂方法与设计模式的工厂方法模式不同(一个是提供一个公有的静态方法,一个是存在工厂类)
优势:
静态工厂方法与构造器不同的第一大优势在于, 他们有名称.
静态工厂方法有自己的方法名,而构造器名称是相同的,只是在参数类型和顺序上有所不同
静态工厂方法与构造器不同的第二大优势在于, 不必在每次调用他们的时候都创建一个新的对象.
这使得不可变类可以使用预先构建好的实例,或者将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象,实例受控的类,如枚举类型
静态工厂方法与构造器不同的第三大优势在于, 他们可以返回原返回类型的任何子类型的对象
这样我们在选择返回对象的类时就有了更大的灵活性.
静态工厂方法的第四大优势在于, 在创建参数化类型实例的时候,他们使代码变得更加简洁.
缺点:
静态工厂方法的主要缺点在于,类如果不含公有的或者受保护的构造器,就不能被子类化.
静态工厂方法的第二个缺点在于,他们与其他的静态方法实际上没有任何区别
总结:
静态工厂方法和公有构造器都各有用处, 我们需要理解他们各自的长处.静态工厂通常更加合适,因此切忌第一反应就是提供公有的构造器,而不先考虑静态工厂.
遇到多个构造器参数时要考虑用构建器
即常用的Builder模式
用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类.
第一种方法:
构造器保持为私有的,并导出公有的静态成员,并且该公有的静态成员是个final域
public class Elvis {
public static final Elvis INSTANCE = new Elvis(); //公有的final域静态成员
private Elvis() {...} //构造器保持私有的
public void leaveTheBuilding() {...}
}
第二种方法:
构造器保持为私有的,提供公有的成员是个静态工厂方法:
public class Elvis {
private static final Elvis INSTANCE = new Elvis(); //私有的final域静态成员
private Elvis() {...} //构造器保持私有的
public static Elvis getInstance() { return INSTANCE;} //公有的静态工厂方法
public void leaveTheBuilding() {...}
}
上述两种方法现实的Singleton类变成可序列化, 仅仅在声明中加入"implements Serializable"是不够的,为了维护并保证Singleton,必须声明所有实例域都是瞬时(transient)的, 并提供一个readResolve方法.否则每次反序列化的实例时,都会创建一个新的实例
http://blog.csdn.net/fg2006/article/details/6409423
第三种方法:
只需编写一个包含单个元素的枚举类型:
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() {...}
}
优点: 更加简洁,无偿地提供了序列化机制,绝对防止多次实例化,虽然没有被广泛使用, 但是单元素的枚举类型已经成为实现Singleton的最佳方法.
通过私有构造器强化不可实例化的能力
举例:
public class UtilityClass {
private UtilityClass() {
throw new AssertionError();
}
}
避免创建不必要的对象
反面例子:
String s = new String("stringette");
改进后:
String s = "stringette";
同时提供了静态工厂方法和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象.
除了重用不可变的对象之外,也可以重用那些已知不会被修改的可变对象
要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱.
消除过期的对象引用
举例:
避免使用终结方法
终结方法通常是不可预测的,也是很危险的,一般情况下是不必要的
http://blog.csdn.net/zs064811/article/details/16813769
java中finalizer终结方法学习心得
最近在看Java的中finalizer终结方法,也就是用来释放内存的,但这绝对和C++中的析构函数不相同
C++中的析构函数是用来回收对象所占用的资源的方法,而在java中,当一个对象不可到达时(也就是重堆栈和静态存储区开始,由引用开始,寻找实体对象),垃圾回收器会释放该对象所相关联的存储空间,并不需要程序员的编码
对于finalizer方法的使用,就只有一条建议--------------尽量不要使用
effective java中有这几个结论
1 不应该依赖终结方法来更新重要的持久状态
如用finalizer方法释放数据库上的永久锁,而且finalizer方法是不一定会被调用的,只有到了内存满了系统才会调用垃圾回收
2 使用终结方法有非常严重的性能损失
而且性能损失还点大
但有两种情况下可以使用
1.当对象所有者忘记调用显示的终结方法(如connection,inputstream,outputstream的close方法和Timer中的cancel方法,这只是一种保险的方法
完全可以由程序员的细心避免的,所以使用这些类的时候千万要记住调用显示的终结方法
2本地对象 也就是其他语言编写的对象托管给java管理,当垃圾回收器回收java对象时,那些本地对象占用的资源是不会回收的,所以这里就需要调用对象的finalizer方法
在说说垃圾回收器
垃圾回收器是用来回收java中无用的对象,也就是不可到达对象,他有很多种机制
1 引用计数器
每一个对象都会用一小块存储空间来存放引用计数器,当对象被引用时,计数器加1,当对象失去引用或对象引用被置为null时减1,当垃圾回收器检测到对象的引用计数器为0时
垃圾回收器释放资源,大家也许会想到资源释放后那空间是不连续的,所以垃圾回收器还整理空间的功能,让空间连续
ps:这里会有一个缺陷,当几个对象引用形成一个循环时,这些对象本来应该被释放的,但由于他的引用计数器不为0,所以垃圾回收器不会释放对象的内存资源
2停止-复制
垃圾回收器回重堆栈和静态存储区开始检查所有引用,当对象是可到达时,就会把可到达的所有对象复制到另外一块存储空间上,而不可到达的便成为垃圾,这种机制的效率是非常低的,因为他会先停止程序,然后执行复制操作,复制的同时还必修改所有引用.完成复制后,空间是连续的,所以就不需要整理。当垃圾(不可到达对象)很少时,这种机制是非常不划算的,所以有了下面的方法
3标记-清扫
速度想当面慢,但垃圾很少时相对于停止-复制是相当快的
从堆栈和静态存储区开始,遍历所有引用,找出存活(可到达)对象并标记,当标记完后开始清理任务,清理后空间是不连续的,所以垃圾回收器还必须整理
如果只用一种机制,是不灵活的
所以了第4种机制
4自适应
对象很稳定时用标记-清扫
垃圾回收器跟踪标记清扫,当碎片很多的时候用停止-复制
如过你发现我说的不对的地方,欢迎说出来大家一起分享