第五十二条、通过接口引用对象
-
如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,就都应该使用接口类型的声明。只有当你利用构造器创建某个对象的时候,才真正需要引用这个对象的类。如:
List<Subscriber> subscribers = new Vector<Subscriber>();
-
如果养成了这个习惯,程序将更加灵活。当决定更换实现的时候,只需要改变构造器中类的名称。周围的代码都可以正常工作,对于这种变化并不在意。
-
如果没有合适的接口存在,完全可以用类而不是接口来引用对象。
比如:值类(String和BigInteger)。值类很少会用多个实现编写,通常是final的,并且很少有对应的接口。
第二种情形是:对象属于一个框架,而框架的基本类型就是类,如果对象属于这种基于类的框架,就应该使用相关的基类(往往是抽象类)来引用这个对象。
最后一种情形是:类实现了接口,但是它提供了接口中不存在的额外方法。
第五十三条、接口优先于反射机制
-
核心反射机制(core reflection facility)
java.lang.reflect
提供了“通过程序访问关于已装载的类的信息”的能力。给定一个Class实例,可以获得Constructor、Method和Field实例,分别代表该Class类所表示的类的Constructor、Method和Field。这些对象提供了“通过程序来访问类的成员名称、域类型、方法签名等信息”的能力。
而且,Constructor、Method、Field实例能够使你通过反射机制操作它们的底层对等体:通过调用上述三项上的方法,可以构造底层类的实例。调用底层类的方法,并访问底层类中的域。
反射机制reflection允许一个类使用另一个类,即使当前者被编译时后者还不存在。
-
反射机制的代价:
-
丧失了编译时类型检查的好处,包括异常检查。
-
执行反射访问所需要的代码非常笨拙和冗长。
-
性能损失:比普通方法要慢不少。
-
-
核心反射机制最初是为了基于组建的应用创建工具而设计的。这类工具需要根据装载类,并且用反射功能找出它们支持哪些方法和构造器。这些工具允许用户交互式地构造出访问这些类的应用程序,但是所产生出来的这些应用程序能够以正确的方式访问这些类,而不是以反射的方式。反射只是在设计的时候被用到。
-
通常,普通应用程序在运行时不应该以反射的方式访问对象。有一些复杂的应用程序需要使用反射机制。比如:类浏览器、对象监视器、代码分析工具、解释型的内嵌式系统。在RPC(远程过程调用)系统中使用反射机制也是十分合适的。
-
反射机制的好处:
对于有些程序,它们必须用到在编译时无法获取的类,但是在编译时存在适当的接口或者超类,通过它们可以引用这个类。以反射方式创建实例,然后通过它们的接口或者超类,正常的方式访问这些实例。
Class.newInstance
方法就已经提供不带参数的构造方法。 -
总结:反射机制是一种功能强大的机制,对于特定的复杂系统编程任务,它是非常必要的,但是它也有一些缺点。如有可能,就应该仅仅使用反射机制来实例化对象,而访问对象时使用编译时已知的某些接口或者超类。
第五十四条、谨慎地使用本地方法
-
Java Native Interface(JNI)允许Java应用调用本地方法Native Method,本地方法是指用本地程序设计语言(如C或C++)来编写特殊的方法。本地方法在本地语言中可以执行任意的计算任务,并返回到Java程序设计语言。
-
本地方法的用途:
-
提供了”访问特定于平台的机制“的能力,比如访问注册表和文件锁。
-
提供了访问遗留代码库的能力,从而可以访问遗留数据。
-
本地方法可以通过本地语言,编写应用程序中注重性能的部分,以提高系统的性能。
-
-
使用本地方法来提高性能的方法不值得提倡:
随着JVM实现变得越来越快。使用本地方法的缺点在于:由于本地语言不是安全的,会引发内存毁坏的错误;由于本地语言是与平台相关的,使用本地方法的应用程序不再是可自由移植的;使用本地方法的程序也更加难以调试。在进入和退出本地方法的时候需要相关固定的开销;胶合代码难以阅读。
第五十五条、谨慎地进行优化
-
三条关于优化的格言:
- 很多计算上的过失都被归咎于效率(没有必要达到的效率)。而不是任何其他的原因——甚至包括盲目地做傻事。
- 不要去计较效率上的一些小小得失,在97%的情况下,不成熟的优化才是一切问题的根源。
- 在优化方面,我们应该遵守两条规则:
- 不要进行优化,
- 还是不要进行优化。
-
优化的弊大于利,尤其是不成熟的优化。这并不意味着,在完成程序之前就可以忽略性能问题,必须要在设计过程中考虑性能问题:努力避免那些限制性能的设计决策;要考虑API设计决策的性能后果。一旦谨慎地设计了程序,并且产生了一个清晰、简明、结构良好的实现,那么就到了考虑优化的时候了。
第五十六条、遵守普遍接受的命名惯例
-
java平台建立了一整套很好的命名惯例naming convention,不严格地说,这些命名惯例分为两大类:字面的(typographical)和语法的(grammatical)。
-
字面的惯例简要的介绍:
-
包的名称应该是层次状的,用句号分割每个部分。每个部分都包括小写字母和数字(很少),任何将在你的组织之外使用的包,其名称都应该以你的组织的Internet域名开头,并且顶级域名放在前面,例如:
edu.cmu
,com.sun
,gov.nsa
。标准类库和一些可选的包,其名称以java和javax开头,这属于这一规则的例外。用户创建的包的名称绝对不能以java和javax开头; -
包名称的剩余部分应该包括一个或者多个描述该包的组成部分。这些描述应该比较简短,一般不超过8个字符,鼓励使用有意义的缩写:如
util
,awt
等。 -
类和接口的名称,包括枚举和注解类型的名称,都应该包括一个或者多个单词,每个单词的首字母大写(如
Timer
和TimerTask
);应该尽量避免缩写。 -
方法和域的名称与类和接口的名称一样,遵循相同的字面惯例,只是第一个字母应该小写。如果首字母缩写组成的单词是一个方法或者域名称的第一个单词,它就应该是小写形式。
-
”常量域“它的名称应该包含一个或者多个大写的单词,中间用下划线符号隔开。
-
局部变量名称的字面惯例与成员名称类似,只不过它也允许缩写,单个字符和短字符序列的意义取决于上下文。
-
参数类型名称通常由单个字母组成:通常是下面五种类型之一:T表示任意的类型;E表示集合的元素类型;K和V表示映射的键和值类型;X表示异常。任何类型的序列都可以是T、U、V或者T1、T2、T3。
-
-
语法命名惯例:比字面惯例更加灵活但是有争议。
-
类通常用一个名词或者名词短语命名;
-
接口的命名与类类似,或者用一个已-able或者-ible结尾的形容词来命名:
Runable
,Iterable
等 -
执行某个动作的方法通常用动词或者动词短语来命名,对于返回boolean值的方法,其名称往往以单词”is“开头,后面跟名词或者名词短语,或者任何具有形容词功能的单词或者短语:
isEmpty
,isEnabled
等 -
如果方法返回被调用对象的一个非boolean的函数或者属性,通常使用名词、名词短语或者以动词”get“开头的动词短语来命名:如
size
,hasCode
或者getTime
。 -
转换对象类型的方法、返回不同类型的独立对象的方法,通常称为toType;
-
返回视图的方法通常称为asType:
asList
-
返回一个与被调用的对象同值的基本类型方法,通常被称为typeValue:
intValue
; -
静态工厂的常用名称为:
valueOf
、of
、getInstance
、newInstance
、getType
和newType
。
-
网友评论