JavaSE_8系列博客——专家之路(一)---Java反射的总结

来源:互联网 发布:宁芙的淘宝店 编辑:程序博客网 时间:2024/05/16 03:41

  • 先来四个基本问题
  • 一什么是反射what
    • 生活中的反射
    • 程序设计语言中的反射
    • Java中的反射
    • 其他语言中的反射
      • NET平台中的反射
  • 二为什么需要反射why
    • 历史原因
    • 反射的好处
    • 反射的应用场景where
  • 三反射的原理how
    • Java中是如何实现反射的
  • 四如何使用反射how
    • 实例演示地址java8官网提供
    • Java反射使用指南网友整理
    • 深入浅出反射网友博文
    • 反射的使用注意事项避坑指南
      • 反射的缺点
      • 程序员在自己的业务开发中应该尽量的远离反射
  • 拓展问题
    • 要实现动态编程除了反射还有
      • AOP
      • IoC
      • 语言级别动态
      • Java中对动态编程的支持
      • NET平台对动态编程的支持
    • 反射可被其他技术替代吗

先来四个基本问题:

一、什么是反射(what)?

生活中的反射

百科定义:反射(外文名reflection),指的是声波、光波或其他电磁波遇到别的媒质分界面而部分仍在原物质中传播的现象。如光的反射、波的反射。

光在两种物质分界面上改变传播方向又返回原来物质中的现象,叫做光的反射

程序设计语言中的反射

百科定义:反射是一种计算机处理方式。有程序可以访问、检测和修改它本身状态或行为的这种能力。能提供封装程序集、类型的对象。(程序集包含模块,而模块包含类型,类型又包含成员。)

Java中的反射

简而言之,通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。

程序中一般的对象的类型都是在编译期就确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

 反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

其他语言中的反射

.NET平台中的反射

https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/reflection

二、为什么需要反射(why)?

历史原因:

http://blog.csdn.net/coder_xia/article/details/14526055
http://blog.csdn.net/sole_ghost/article/details/1561646

反射的好处

运行期类型的判断,动态类加载,动态代理使用反射。

  1. 带来更好的扩展性,增加程序的灵活性。避免将程序写死到代码里

  2. 提供类查看器的功能,在IDE中帮助人们更好更快更简单的进行编程。

    当我们在使用IDE(如Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射

  3. 调试和测试工具中,我们将广泛应用反射的特性,去检查所有类中的成员、对象中的各种成员

反射的应用场景(where)?

1)Java的反射机制在做基础框架的时候非常有用,有一句话这么说来着:反射机制是很多Java框架的基石。而一般应用层面很少用,不过这种东西,现在很多开源框架基本都已经给你封装好了,自己基本用不着写。典型的除了Hibernate之外,还有Spring也用到很多反射机制。经典的就是在xml文件或者properties里面写好了配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射机制,根据这个字符串获得某个类的Class实例,这样就可以动态配置一些东西,不用每一次都要在代码里面去new或者做其他的事情,以后要改的话直接改配置文件,代码维护起来就很方便了,同时有时候要适应某些需求,Java类里面不一定能直接调用另外的方法,这时候也可以通过反射机制来实现。
总的来说,自己写的很少,具体什么时候要用那要看需求,反射机制无非就是根据一个String来得到你要的实体对象,然后调用它原来的东西。但是如果是要自己写框架的话,那就会用得比较多了。

2)当你做一个软件可以安装插件的功能,你连插件的类型名称都不知道,你怎么实例化这个对象呢?因为程序是支持插件的(第三方的),在开发的时候并不知道 。所以无法在代码中 New出来 ,但反射可以,通过反射,动态加载程序集,然后读出类,检查标记之后再实例化对象,就可以获得正确的类实例。

3)在编码阶段不知道那个类名,要在运行期从配置文件读取类名, 这时候就没有办法硬编码new ClassName(),而必须用到反射才能创建这个对象.反射的目的就是为了扩展未知的应用

三、反射的原理(how)

Java中是如何实现反射的?

小结:其实,用最简单的方式来说。反射的实现原理,就和我们生活中的镜面反射是一个道理,怎么实现镜面的反射?一个最简单的做法,就是用一面镜子,把隐藏在另外一个地方的信息,通过利用镜面把这些被封装好,隐藏好的信息反射出来,这样我们通过镜子就可以看到原本我们不能看到的东西。所以,在Java中,实现反射也是同样的道理,详情,可以参见Java中反射框架的实现。通过将class文件(字节码文件对象)中的所有信息,通过遍历的方式对其进行分门别类,获取这些信息,并分门别类的进行存储(赋值给某个对象),然后再返回这些信息。通过JDK本身提供的框架,我们就能够获取到这些信息。简单来说,可以分为以下几步:
  

  1. 获得Class对象,就是获取到指定的名称的字节码文件对象。

  2. 实例化对象(创建指定类的对象),获得类的属性、方法或构造函数。

  3. 获取类中的方法,属性,构造函数

参考博客:
http://www.cnblogs.com/makaruila/p/4852554.html

http://www.sczyh30.com/posts/Java/java-reflection-2/

四、如何使用反射?(how)

实例演示地址(java8官网提供)

https://docs.oracle.com/javase/tutorial/reflect/index.html

Java反射使用指南(网友整理)

http://ifeve.com/java-reflection/

深入浅出反射(网友博文)

https://zhuanlan.zhihu.com/p/21423208

反射的使用注意事项(避坑指南)

反射的缺点:

任何事物,都有两面性,反射的优点,也同是就是它的缺点,所以,没有好与坏,只有最合适的场景,一阴一阳,才是天道平衡的条件。

(1)使用反射的性能较低
(2)使用反射相对来说不安全
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性

程序员在自己的业务开发中应该尽量的远离反射

反射:在流行的库如Spring和Hibernate中,反射自然有其用武之地。不过内省业务代码在很多时候都不是一件好事,原因有很多,一般情况下我总是建议大家不要使用反射。
这里写图片描述
首先是代码可读性与工具支持。打开熟悉的IDE,寻找你的Java代码的内部依赖,很容易吧。现在,使用反射来替换掉你的代码然后再试一下,结果如何呢?如果通过反射来修改已经封装好的对象状态,那么结果将会变得更加不可控。请看看如下示例代码:

如果这样做就无法得到编译期的安全保证。就像上面这个示例一样,你会发现如果getDeclaredField()方法调用的参数输错了,那么只有在运行期才能发现。要知道的是,寻找运行期Bug的难度要远远超过编译期的Bug。

最后还要谈谈性能代价问题。JIT对反射的优化程度是不同的,有些优化时间会更长一些,而有些甚至是无法应用优化。因此,有时反射的性能损失可以达到几个数量级的差别。不过在典型的业务应用中,你可能不会注意到这个代价。

反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

总结一下,我觉得在业务代码中唯一合理(直接)使用反射的场景是通过AOP。除此之外,你最好远离反射这一特性。

拓展问题:

要实现动态编程,除了反射还有……?

AOP?

严格意义上来说,AOP不是实现动态编程的技术,AOP是一种编程思想,要实现AOP需要利用一些动态编程的技术,例如:反射、动态编译等动态编程的手段和技术,来达到动态控制程序的效果。

IoC?

同AOP的解释,需要用到动态编程技术来实现,但IoC本身并不是动态编程技术。要实现IoC需要利用一些动态编程的技术,例如:反射、动态编译等动态编程的手段和技术,来达到动态控制程序的效果。

语言级别动态

动态语言的示例有:Lisp、Smalltalk、JavaScript、PHP、Ruby、Python、ColdFusion、Lua、Cobra 和 Groovy。

大多数动态语言都会向开发人员提供以下优点:

  • 可以使用快速反馈循环(REPL 或读取-计算-打印循环)。 这样,您就可以在输入几条语句之后立即执行它们以查看结果。
  • 同时支持自上而下的开发和更传统的自下而上的开发。 例如,当您使用自上而下的方法时,可以调用尚未实现的函数,然后在需要时添加基础实现。
  • 更易于进行重构和代码修改操作,原因是您不必在代码中四处更改静态类型声明。
  • 利用动态语言可以生成优秀的脚本语言。 利用新的命令和功能,客户可以轻松地扩展使用动态语言创建的应用程序。
  • 动态语言还经常用于创建网站和测试工具、维护服务器场、开发各种实用工具以及执行数据转换。

Java中对动态编程的支持

主要有以下三个方面的支持

  • 反射

  • 动态编译(生成字节码)

  • 调用JavaScript引擎

http://blog.csdn.net/star_sky_red/article/details/54586145

https://www.ibm.com/developerworks/cn/java/coretech/java-dynamic.html

.NET平台对动态编程的支持

https://msdn.microsoft.com/zh-cn/library/650ax5cx(v=vs.110).aspx

反射可被其他技术替代吗?

答案是:既可以,又不可以。

说它可以,是技术的可行性上来说,技术上可以做到在反射的某些应用场景可以使用其他技术来达到和反射一样的效果。哪些应用场景?在动态生成一个类、对象的时候,例如这篇文章中提到的,当反射成为了应用程序的性能瓶颈时,可以考虑使用代码生成来取代反射:https://www.ibm.com/developerworks/cn/java/j-dyn0610/

说它不可用,是说应用场景的不一样,反射有很多的其他的应用场景,其作用是不可替代的。不仅仅是局限在运行时创建和调用类型实例。在运行时,查看类、对象、方法、属性等信息,也是反射所提供的一大好处。具体的应用:Java提供的注解机制,就利用了反射的这个功能,在运行时获取类、对象的属性和方法来完成相关的逻辑判断和处理。

阅读全文
1 0