只需五分钟 读完 Effective Java

Effective Java

创建和销毁对象---考虑用静态工厂方法代替构造器

构造器是创建一个对象实例最基本也最通用的方法,大部分开发者在使用某个class的时候,首先需要考虑的就是如何构造和初始化一个对象示例,而构造的方式首先考虑到的就是通过构造函数来完成,因此在看javadoc中的文档时首先关注的函数也是构造器。所以对于类而言,我们为了获得一个类的实例对象,通常情况下会提供一个公有的(public) 的构造器。当然除了这种方法以外,我们还可以通过给类提供一个public的静态工厂方法(static factory method)的方式来完成,让它返回一个类的实例。如:

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

这个示例将boolean基本类型值转换成一个Boolean对象的引用。(需要注意的是这里的静态工厂方法与设计模式中所说的工厂方法模式不同)那么,在Effective Java的首篇中,我们来看看静态工厂方法相比于构造器带来了哪些优势:1. 静态工厂方法可以有不同的名称,代码更清楚,更易读。在框架设计中,针对某些工具类通常会考虑空对象以辨别该对象是否已经被初始化。构造器的命名都一致,一个类只能有一个指定签名的构造器。当一个类需要提供多个构造器时,通常只是通过不同的形参类型的顺序加以区分,但其函数名还是相同的,无法提供较高的区分度。那么,当一个类需要多个带有相同签名的构造器时,不妨考虑用静态工厂方法代替构造器,并且慎重地选择名称以便突出它们之间的区别。这样该静态工厂方法有名称,通过赋予有意义的名称,使用该方法的程序员可以清晰的知道该方法的含义。(方法的签名(signature)由它的名称和所有参数的返回类型组成,而不包括它的返回类型)2. 静态工厂方法不必在每次调用它们的时候都创建一个新对象。比如你可以在静态工厂方法里限定创建该对象的个数,当超出规定的个数时,返回缓存里的对象。场景:调用构造器时每次都创建新对象。这一点很显然,我们知道Singleton其实也提供一个静态工厂方法获取实例。除此之外,可以用==代替equals()方法,达到性能的提升。3. 静态工厂方法可以返回原返回类型的任何子类型的对象。场景:构造器只能返回当前类的实例,无法返回子类的实例。这个优点的确很有用,能够充分利用多态,使代码更具有可扩展性。设计模式中的工厂方法也有体现,可根据入参type返回类型为Types的不同子类实例。

public Types getType(String type) {...}

这样我们在选择返回对象的类时就有更大的灵活性,这种灵活性的应用就是API可以返回对象,同时又不会使对象的类变成公有的。以这种方式隐藏实现类会使API变得简洁。这项技术适合于基于接口的框架(interface-based framework)。这种面向接口的编程也提高了软件的可维护性和性能。4. 静态工厂方法在创建参数化类型实例的时候使代码变得更加简洁。场景: Java的泛型类在实例化时,还是需要写两次类型参数,非常冗长。静态工厂方法可以帮你改善这种情况:举个例子,假设在HashMap类中提供如下静态工厂方法:

public static <k, v=""> HashMap<k, v=""> newInstance(){
   return new HashMap<k, v="">();
}

那么,调用时应该是这样的:

HashMap<stirng, list<string="">> m = HashMap.newInstance();

而在调用参数化的构造器时,则通常需要这样做,显得比较繁琐。

HashMap<string, list<string="">> m = new HashMap<string, list<string="">>();
 

另外值得一提的是,静态工厂方法返回的对象所属的类,在编写包含该静态工厂方法的类时不必存在。这种灵活的静态工厂方法构成了服务提供者框架(Service Provider Framework)的基础,例如JDBC的API。所谓服务提供者框架是指这样的一个系统:多个服务提供者实现同一个服务,由框架(即系统)来负责为客户端提供这种服务的多个实现并将这些实现解耦。服务提供者框架有三个主要的组件:1.服务接口(Service interface),这是提供者实现的。2.提供者注册API(Provider Registration API),这是系统用来注册实现,让客户端访问它们的。3.服务访问API(Service Access API),这是客户端获取服务实例用的。另外还有第四个可选接口,服务提供者接口(Service Provider Interface),负责创建其服务实现的实例。若没有服务提供者接口,实现就按照类名称进行注册,并通过反射方式进行实例化。对JDBC而言,Connection就是它的服务接口,DriverManager.registerDriver就是它的提供者注册API,DriverManager.getConnection是服务访问API,Driver就是服务提供者接口。

如提供了两个静态工厂方法empty和preallocate(含义,重新分配;再指派)用于分别创建一个空对象和一个带有指定分配空间的String对象。从使用方式来看,这些静态方法确实提供了有使用者很容易就可以判断出它们的作用和应用场景,而不必在一组重载的构造器中去搜寻每一个构造函数及其参数列表,以找出适合当前场景的构造函数。

从效率方面来讲,由于提供了唯一的静态空对象,当判读对象实例是否为空时(isEmpty),直接使用预制静态空对象(emptyString)的地址与当前对象进行比较,如果是同一地址,即可确认当前实例为空对象了。对于preallocate函数,顾名思义,该函数预分配了指定大小的内存空间,后面在使用该String实例时,不必担心赋值或追加的字符过多而导致频繁的realloc(重新分配内存)等操作。2.不必在每次调用它们的时候创建一个新的对象。还是基于上面的代码实例,由于所有的空对象都共享同一个静态空对象,这样也节省了更多的内存开销,如果是strEmpty2方式构造出的空对象,在执行比较等操作时会带来更多的效率开销。事实上,Java在String对象的实现中,使用了常量资源池也是基于了同样的优化策略。该优势同样适用于单实例模式。3.可以返回原返回类型的任何子类型。在Java Collections Framework的集合接口中,提供了大量的静态方法返回集合接口类型的实现类型,如Collections.subList()、Collections.unmodifiableList()等。返回的接口是明确的,然而针对具体的实现类,函数的使用者并不也无需知晓。这样不仅极大的减少了导出类的数量,而且在今后如果发现某个子类的实现效率较低或者发现更好的数据结构和算法来替换当前实现子类时,对于集合接口的使用者来说,不会带来任何的影响。本书在例子中提到EnumSet是通过静态工厂方法返回对象实例的,没有提供任何构造函数,其内部在返回实现类时做了一个优化,即如果枚举的数量小于64,该工厂方法将返回一个经过特殊优化的实现类实例(RegularEnumSet),其内部使用long(64bits在Java中)中的不同位来表示不同的枚举值。如果枚举的数量大于64,将使用long的数组作为底层支撑。然而这些内部实现类的优化对于使用者来说是透明的。4.在创建参数化类型实例的时候,它们使代码变得更加简洁。Map<String,String> m = new HashMap<String,String>(); 由于Java在构造函数的调用中无法进行类型的推演,因此也就无法通过构造器的参数类型来实例化指定类型参数的实例化对象。然而通过静态工厂方法则可以利用参数类型推演的优势,避免了类型参数在一次声明中被多次重写所带来的烦忧,见如下代码:

时间: 2024-08-29 21:51:14

只需五分钟 读完 Effective Java的相关文章

Java是什么?只需5分钟,了解java必须要知道的知识点

不清楚Java是什么?只需5分钟,了解java必须要懂的知识点 Java吸取了C++面向对象的概念,将数据封装于类中,利用类的优点,实现了程序的简洁性和便于维护性.下面是我收集的Java必备基础知识点,希望对你有用. 1. 简述Java的基本历史 Java起源于SUN公司的一个GREEN的项目,其原先目的是:为家用消费电子产品发送一个信息的分布式代码系统,通过发送信息控制电视机.冰箱等. 2. Java特点 简单的.面向对象的.分布式的.安全的.稳定的.与平台无关的.可解释的.多线的.动态的语言

Java是什么?只需5分钟,了解java必须要懂的知识点

Java是什么?Java吸取了C++面向对象的概念,将数据封装于类中,利用类的优点,实现了程序的简洁性和便于维护性.下面是我收集的Java必备基础知识点,希望对你有用.1. 简述Java的基本历史Java起源于SUN公司的一个GREEN的项目,其原先目的是:为家用消费电子产品发送一个信息的分布式代码系统,通过发送信息控制电视机.冰箱等.2. Java特点简单的.面向对象的.分布式的.安全的.稳定的.与平台无关的.可解释的.多线的.动态的语言.3. 什么是Java?Java:一种编程语言.一种开发

如何对比Python和Java,只需三分钟告诉你!

Java和Python两门语言都是目前非常热门的语言,可谓北乔峰南慕容,二者不分上下,棋逢对手.但是对于初学者来说,非常困惑,因为时间和精力有限,上手必须要先学一门,到底选那个好呢,今天3分钟带你透彻了解. 1.运行速度 java是静态语言静态编译的,速度上要比Python快的很多,而Python动态类型语言,一边执行一边编译,速度要上慢一些. 2.对Legacy代码的支持 对于legacy代码的支持,由于Java大量的用于电商,互联网后端,银行等大型系统,所以对于legacy的代码的数量要远大

二手手机回收:估价+回收只需3分钟

一台烹饪机器人2分半钟炒出一盘虾仁;只需要喷一次水,就能让道路扬尘大幅降低的抑尘剂……昨日,第八届北京国际节能环保展在北京展览馆开幕,众多跟市民生活息息相关的高科技环保产品亮相. 据了解,展览将持续到6月11日,市民可凭有效证件前往免费观展. 路面固化剂: 一吨防尘剂可省4万吨水 在低碳环保节能展上,一种用来防止道路扬尘的路面固化剂成为热门. 首创集团北京精诚博桑科技公司副总经理徐若松介绍说,现在降低城市路面扬尘主要靠喷水.但是,几十分钟后,喷到路面上的水就被蒸发了,降尘效果不明显.如果将这款高

js只需5分钟创建一个跨三大平台纯原生APP

DeviceOne之前介绍过了,现在来介绍一下DeviceOne快速开发到什么程度 使用js只需要5分钟就可以打出垮Android.ios.windows三大平台的纯原生UI的安装包. 只需要6个小时,就可以画出仿微信的四个页面. 只需要10个小时,就可以画出仿墨迹天气的三个页面. DeviceOne地址:http://www.deviceone.net QQ群:365443130 请看效果图:

卓越培训:只需五步,让你轻松学好Java!

俗话说磨刀不误砍柴工,无论学习什么语言,都还是要讲究一些技巧,那么如何学Java呢?中软卓越Java培训老师为大家总结快速学习Java的5个步骤,帮你4个月学会Java. 1.确定学习java的决心.万事开头难,其实对于编程来说,开头并不是那么难,因为开始学习编程的小伙伴基本上都有兴趣点,有一腔热血挺过入门问题不大,学习编程只靠一腔热血还是不够的,贵在坚持,很多人都是倒在坚持的路上,半途而废,学习编程其实也没啥好的捷径就是先搞懂理论,然后开始不停的练习实践,反反复复,其实这个过程都知道要经历多少

只需2分钟,简单构建velocity web项目

Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象 velocity的语法非常简单.这里不多介绍. 我们平时的web项目,通常的开发流程是前端写好静态页面.后端将静态页面改成jsp,在相应的需要替换数据的地方,使用 jstl.EL表达式等接收action模块传递过来的数据.一般使用action来处处理参数,调用service层来处理业务逻辑,service层调用da

Android Studio 主题及字体修改,只需五步

在我们刚学习Android Studio时,最初可能就是Android Studio主题及字体的修改.其实很简单,只需要简单的五步. 1.打开设置功能窗口.两种方式: a. [File]菜单-->打开[Settings]选项: b. 工具栏中选中[Settings]图标打开. 2.找到[Appearance &Behavior]-->Appearance选项,IDE默认[theme]为Intellij主题.如图: 3.如上图,点击[Theme]下拉选项,选中[Darcula]主题,点击

产品开发阵容的重要性:APP开发只需五步

最早认识的一个朋友是程序员,曾经到一家外包公司接单子,小外包公司经常遇到的问题就是和需求方谈产品功能.客户要做外包,对方让他一次性报价,但是客户连功能点自己都不清楚,这时朋友说还是按照具体功能点来做吧.但是客户坚持先给个估价才会考虑做不做,最终朋友在不得已的情况下给了个价钱,结果遇到另外一个程序员只报了他一半的价格去做这个单子..... 可想而知,当开发成本和需求不匹配的情况下,项目失败是必然的! 这种情况在我们目前创业的项目程序员客栈屡见不鲜,其实目前全世界都是类似的这样外包不靠谱的情况.不过