Effective Java 读书笔记(一)

创建和销毁对象

  1. 何时以及如何创建对象?
  2. 何时以及如何避免创建对象?
  3. 如何确保它们能够适时地销毁?
  4. 如何管理对象销毁之前必须进行的各种清理动作?

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

类可以提供一个公有的静态工厂方法,它只是一个返回类的实例的静态方法。使用这种方法来代替构造器。
下面是一个来自Boolean(基本类型boolean的装箱类)的简单示例。这个方法将boolean基本类型值转换成了一个Boolean对象引用:

public static Boolean valueOf(boolean b) {
	return b ? Boolean.TRUE:Boolean.FALSE;
}

静态工厂方法代替构造器的优势

1. 静态工厂方法与构造器不同的第一大优势在于,它们有名称。
例如:BigInteger(int,int,Random)返回的BigInteger可能为素数,如果用名为BigInteger.probablePrime的静态工厂方法来表示,更清晰。还有,一个类只能有与类名相同的构造器,可以重载,那面对这样的构造器,用户在创建实例的时候那一选择,在这种情况下,静态工厂方法可以很好的解决这类问题。

2. 静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新对象。
例如:Boolean.valueOf(boolean)方法体现了这方面的优势:它从来不创建对象。这种方法类似于享元(Flyweight)模式。如果程序经常请求创建相同的对象,并且创建对象的代价很高,则方法可以极大地提升性能。
静态工厂方法能够为重复的调用返回对象,这样有助于类总能严格控制在某个时刻哪些实例应该存在。这种类被称为实例受控的类(instance-controlled)。编写实例受控类有几个原因。实例受控使得类可以确保它是一个Singleton或是不可实例化的。它还使得不可变的值类可以确保不会存在两个相等的实例,即当且仅当a==b时,a.equals(b)才为true。这是享元模式的基础。枚举类型也保证了这一点。

3. 静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类型的对象。
这种灵活性的一种应用是,API可以返回对象,同事又不会使对象的类变成公有的。以这种方式隐藏实现类会使API变得非常简洁。这项技术适用于基于接口的框架(interface-based framework),因为在这种框架中,接口为静态工厂方法提供了自然返回类型。
在Java8之前,接口不能有静态方法,因此按照惯例,接口Type的静态工厂方法被放在一个名为Types的不可实例化的伴生类中。例如,Java Collections Framework些实现都通过静态工厂方法在一个不可实例化的类(java.util.Collections)中导出。所有返回对象的类都是非公有的。
现在的Collections Framework API比导出45个独立公有类的哪种实现方式要小得多,每种便利实现都对应一个类。这不仅仅是指API数量上的减少,也是概念意义上的减少:这样可以降低API的难度和数量。此外,使用这种静态工厂方法时,甚至要求客户端通过接口来引用被返回的对象,而不是通过它的实现类来引用被返回的对象,这是一中良好的习惯。

4. 静态工厂的第四大优势在于,所返回的对象的类可以随着每次调用而发生变化,这取决于静态工厂方法的参数值
只要是已声明的返回类型的子类型,都是允许的。返回对象的类也可能随着发行版本的不同而不同。
EnumSet没有公共的构造器,只有静态工厂方法。在OpenJDK实现中,它们返回两种子类之一的一个实例,具体则取决于底层枚举类型的大小:如果它的元素有64个或者更少,就像大多数枚举类型一样,静态工厂方法就会返回一个RegalarEumSet实例,用单个long进行支持;如果枚举类型有65个或者更多元素,工厂就返回JumBoEnumSet实例,用一个long数据进行支持。
这两个实现类的存在对于客户端来说是不可见的。如果RegularEnumSet不能再给小的枚举类型提供性能优势,就可能从未来的发行版本中将它删除,不会造成任何负面的影响。同样地,如果事实证明对性能有好处,也可能在未来的发行版本中添加第三甚至第四个EnumSet实现。客户端永远不知道也不关心它们从工厂方法中得到的对象的类,它们只关心它是EnumSet的某个子类。

5. 静态工厂的第五大优势在于,方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不存在。
这种灵活的静态工厂方法构成了服务提供者框架(Service Provider Framework)的基础,例如JDBC(Java数据库连接)API。服务提供者框架是指这样一个系统:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把它们从多个实现中解耦出来。
服务提供者框架中有三个重要的组件:服务接口(Service Interface),这是提供者实现的;提供这注册API(Provider Registration API),这是提供者用来注册实现的;服务访问者API(Service Access API),这是客户端用来获取服务的示例。服务访问API是客户端用来指定谋者选择实现的条件。如果没有这样的规定,API就会返回默认实现的一个实例,或者允许客户端便利所有可用的实现。服务访问API是“灵活的静态工厂”,它构成了服务提供者框架的基础。
服务提供者框架的第四个组件服务提供者接口(Service Provider interface)是可选的,它表示产生服务接口之实例的工厂对象。如果没有服务提供者接口,实现就通过反射方式进行实例化。对于JDBC来说,Connection就是其服务接口的一部分,DriverManager.registerDriver是提供者注册API,DriverManager.gerConnection是服务访问API,Driver是服务提供者接口。
服务提供者框架模式有着无数中变体。例如,服务访问API可以返回比提供者需要的更丰富的服务接口。这就是桥接模式。依赖注入框架可以被看作是一个强大的服务提供者。从Java 6 版本开始,Java平台就提供了一个通用的服务提供者框架java.util.ServiceLoader,因此你不需要(一般来说也不应该)在自己编写了。JDBC不用ServiceLoader。

静态工厂方法的缺点

1. 静态工厂方法的主要缺点在于,类如果不含公有的或者受保护的构造器,就不能被子类化。

2. 静态工厂方法的第二个缺点在于,程序员很难发现它们。
下面举一些静态工厂方法的惯用名称

  • from————类型转换方法,它只有单个参数,返回该类型的一个相对应的实例。
  • of————聚合方法,带有多个参数,返回该类型的一个实例,把它们合并起来
  • valueOf————比from和of更烦琐的一种替代方法
  • instance或者getInstance——返回的实例是通过方法(如有)参数来描述的,但是不能说与参数具有同样的价值
  • create或者newInstance————想instance或者getInstance一样,但create或者newInstance能够确保每次调用都返回一个新的实例
  • getType————想getInstance一样,但是在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。
  • newType————像newInstance一样,但是在工厂方法处于不同的类中的时候使用。
  • type————getType和newType的简版
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值