第53条:接口优先于反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

核心反射机制 java.lang.reflect,提供了“通过程序来访问关于已装载的类的信息”的能力。给定一个Class实例,你可以获得Constructor、Method和Field实例,分別代表了该Class实例所表示的类的Constructor( 构造器)、Method( 方法)和Held( 域)。这些对象提供了“通过程序来访问类的成员名称、域类型、方法签名等信息”的能力。

而且,Constructor、Method和Field实例使你能够通过反射机制操作它们的底层对等体:通过调用Constructor、Method和Field实例上的方法,可以构造底层类的实例、调用底层类的方法,并访问底层类中的域。例如,Method.invoke使你可以调用任何类的任何对象上的任何方法(遵从常规的安全限制)反射机制(reflection )允许一个类使用另一个类,即使当前者被编译的时候后者还根本不存在。然而,这种能力也要付出代价:

       • 丧失了编译时类型检查的好处,包括异常检査。如果程序企图用反射方式调用不存在的或者不可访问的方法,在运行时它将会失败,除非采取了特别的预防措施。

       • 执行反射访问所需要的代码非常笨拙和冗长。编写这样的代码非常乏味,阅读起来也很困难。

       • 性能损失。反射方法调用比普通方法调用慢了许多。具体慢了多少,这很难说,因为受到了多个因素的影响。在我的机器上,速度的差异可能小到2倍,也可能大到50倍。

核心反射机制最初是为了基于组件的应用创建工具而设计的。这类工具通常要根据需要装载类,并且用反射功能找出它们支持哪些方法和构造器。这些工具允许用户交互式地构建出访问这些类的应用程序,但是所产生出来的这些应用程序能够以正常的方式访问这些类,而不是以反射的方式。反射功能只是在设计时被用到。通常,普通应用程序在运行时不应该以反射方式访问对象。

有一些复杂的应用程序需要使用反射机制。这些示例中包括类浏览器、对象监视器、代码分析工具、解释型的内嵌式系统。在RPC( 远程过程调用)系统中使用反射机制也是非常合适的,这样可以不再需要 。如果你对自己的应用程序是否也属于这一类应用程序而感到怀疑,它很有可能就不属于这一类。

如果只是以非常有限的形式使用反射机制,虽然也要付出少许代价,但是可以获得许多好处。对于有些程序,它们必须用到在编译时无法获取的类,但是在编译时存在适当的接口或者超类,通过它们可以引用这个类(见第52条:通过接口引用对象)。如果是这种情况,就可以以反射方式创建实例, 然后通过它们的接口或者超类,以正常的方式访问这些实例。如果适当的构造器不带参数,甚至根本不需要使用java.lang.reflect包,Class.newlnstance方法就已经提供了所需的功能。

例如,下面的程序创建了一个Set<String>实例,它的类是由第一个命令行参数指定的。 该程序把其余的命令行参数插入到这个集合中,然后打印该集合。不管第一个参数是什么,程序都会打印出余下的命令行参数,其中重复的参数会被消除掉。这些参数的打印顺序取决于第一个参数中指定的类。如果指定“java.util.HashSet”,显然这些参数就会以随机的顺序打印出来,如果指定“java.util.TreeSet”,则它们就会按照字母顺序打印出来,因为TreeSet中的元素是排好序的。相应的代码如下:

尽管这个程序就像一个“玩偶”,但是它所演示的这种方法是非常强大的。这个玩偶程序可以很容易地变成一个通用的集合测试器,通过侵入式地操作一个或者多个集合实例,并检査是否遵守Set接口的约定,以此来验证指定的Set实现。同样地,它也可以变成一个通用的集合性能分析工具。实际上,它所演示的这种方法足以实现一个成熟的服务提供者框架 ( 见第1条:考虑用静态工厂方法代替构造器)。绝大多数情况下,使用反射机制时需要的也正是这种方法。

这个示例演示了反射机制的两个缺点。第一,这个例子会产生3个运行时错误,如果不使用反射方式的实例化,这3个错误都会成为编译时错误。第二,根据类名生成它的实例需要20行冗长的代码,而调用一个构造器可以非常简洁地只使用一行代码。然而,这些缺点还仅仅局限于实例化对象的那部分代码。一旦对象被实例化,它与其他的Set实例就难以区分。在实际的程序中,通过这种限定使用反射的方法,绝大部分代码可以不受影响。

如果试着编译这个程序,会得到下面的错误消息:

这条警告与程序中使用了泛型有关,但它并不能说明真正的问题。要了解禁止这种警告的最佳方法,(请参见第24条:消除非受检警告)。

另一个值得注意的附带问题是,这个程序使用了System.exit。很少有需要调用这个方法的时候,它会终止整个VM(虚拟机)。但是,它对于命令行有效性的非法终止是很合适的。

类对于在运行时可能不存在的其他类、方法或者域的依赖性,用反射法进行管理,这种用法是合理的,但是很少使用。如果要编写一个包,并且它运行的时候必须依赖其他某个包的多个版本,这种做法可能就非常有用。这种做法就是,在支持包所需要的最小环境下对它进行编译,通常是最老的版本,然后以反射方式访问任何更加新的类或者方法。如果企图访问的新类或者新方法在运行时不存在,为了使这种方法有效你还必须采取适当的动作。所谓适当的动作,可能包括使用某种其他可替换的办法来达到同样的目的,或者使用简化的功能进行处理。

简而言之,反射机制是一种功能强大的机制,对于特定的复杂系统编程任务,它是非常必要的,但它也有一些缺点。如果你编写的程序必须要与编译时未知的类一起工作,如有可能,就应该仅仅使用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容