第2章-创建和销毁对象

来源:互联网 发布:苏州德威国际学校 知乎 编辑:程序博客网 时间:2024/06/05 16:35

创建和销毁对象

考虑用静态工厂方法代替构造器

对于类而言,为了让客户端获取他自身的一个实例,最常用的方法就是提供一个公有的构造器.

还有一种方法,类可以提供一个公有的静态工厂方法,他只是一个返回类的实例的静态方法.

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

 

 

 

javafinalizer终结方法学习心得

最近在看Java的中finalizer终结方法,也就是用来释放内存的,但这绝对和C++中的析构函数不相同

C++中的析构函数是用来回收对象所占用的资源的方法,而在java中,当一个对象不可到达时(也就是重堆栈和静态存储区开始,由引用开始,寻找实体对象),垃圾回收器会释放该对象所相关联的存储空间,并不需要程序员的编码

对于finalizer方法的使用,就只有一条建议--------------尽量不要使用

effective  java中有这几个结论

1   不应该依赖终结方法来更新重要的持久状态

如用finalizer方法释放数据库上的永久锁,而且finalizer方法是不一定会被调用的,只有到了内存满了系统才会调用垃圾回收

2    使用终结方法有非常严重的性能损失

而且性能损失还点大

 但有两种情况下可以使用

1.当对象所有者忘记调用显示的终结方法(如connectioninputstreamoutputstreamclose方法和Timer中的cancel方法,这只是一种保险的方法

  完全可以由程序员的细心避免的,所以使用这些类的时候千万要记住调用显示的终结方法

2本地对象  也就是其他语言编写的对象托管给java管理,当垃圾回收器回收java对象时,那些本地对象占用的资源是不会回收的,所以这里就需要调用对象的finalizer方法

在说说垃圾回收器

垃圾回收器是用来回收java中无用的对象,也就是不可到达对象,他有很多种机制

1 引用计数器

每一个对象都会用一小块存储空间来存放引用计数器,当对象被引用时,计数器加1,当对象失去引用或对象引用被置为null时减1,当垃圾回收器检测到对象的引用计数器为0

垃圾回收器释放资源,大家也许会想到资源释放后那空间是不连续的,所以垃圾回收器还整理空间的功能,让空间连续

ps:这里会有一个缺陷,当几个对象引用形成一个循环时,这些对象本来应该被释放的,但由于他的引用计数器不为0,所以垃圾回收器不会释放对象的内存资源

2停止-复制

垃圾回收器回重堆栈和静态存储区开始检查所有引用,当对象是可到达时,就会把可到达的所有对象复制到另外一块存储空间上,而不可到达的便成为垃圾,这种机制的效率是非常低的,因为他会先停止程序,然后执行复制操作,复制的同时还必修改所有引用.完成复制后,空间是连续的,所以就不需要整理。当垃圾(不可到达对象)很少时,这种机制是非常不划算的,所以有了下面的方法

3标记-清扫

速度想当面慢,但垃圾很少时相对于停止-复制是相当快的

从堆栈和静态存储区开始,遍历所有引用,找出存活(可到达)对象并标记,当标记完后开始清理任务,清理后空间是不连续的,所以垃圾回收器还必须整理

如果只用一种机制,是不灵活的

所以了第4种机制

4自适应

对象很稳定时用标记-清扫

垃圾回收器跟踪标记清扫,当碎片很多的时候用停止-复制

如过你发现我说的不对的地方,欢迎说出来大家一起分享

 

 

 

原创粉丝点击