目录
前言
考虑一个场景,在程序运行时,一个对象想要检查自己所拥有的成员变量属性,该如何操作?另外一个场景,想要在运行期获得某个类的Class信息如它的属性、构造方法、一般方法后再考虑是否创建它的对象,这种情况就需要用到反射!
1)java文件在编译后会变成.Class文件,这就像是个镜面,本身是.Java,在镜中是.Class,他们其实是一样的;同理,看到镜子的反射是.Class,就能通过反编译,了解到.Java文件的本来面目。
2)对于反射,官方给出的概念:反射是Java语言的一个特性,它允许在程序运行时(注意不是编译的时候)来进行自我的检查并且对内部的成员进行操作。例如它允许一个Java类获取它所有的成员变量和方法并且显示出来。
3)反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在Java中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息
4)反射是Java中的一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时进行装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知类的名字。
反射机制的作用
1)在运行时判断任意一个对象所属的类
2)在运行时获取类的对象
3)在运行时访问java对象的属性,方法,构造方法等
首先需要搞清楚为什么要反射机制?这就涉及到了动态与静态的概念。
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,降低类之间的耦合性。
IOC容器的技术剖析
1)IOC中最基本的技术就是“反射(Reflection)”编程,通俗来讲就是根据给出的类名(字符串方式)来动态的生成对象,这种编程方式可以让对象在生成时才被决定到底是哪一种对象。只是在spring中要生产 的对象都在配置文件中给出定义,目的就是提高灵活性和可维护性;
2)目前C#、Java和PHP5等语言均已支持反射,其中PHP5的技术书籍中,有时候也被译成“映射”。有关反射的概念和用法,大家应该都很清楚,反射的应用是很广泛的,很多的成熟框架,比如像Java中的Hibernate、Spring框架,。NET中的NHibernate、Spring.NET框架都是把“反射”作为最基本的技术手段;
3)反射技术其实很早就出现了,但是一直被忽略,没有被进一步的利用,当时的反射编程方式相对于正常的对象生成方式要慢至少10倍,现在的反射技术经过改良优化,已经非常成熟,反射方式生成对象和通常对象生成方式,速度已经相差不大了,大约是1-2倍的差距。
4)我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看做是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言提供的反射机制,根据配置文件给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为有配置问价来定义,也就是把工厂和对象生成的这两者独立分割开来,目的就是提高灵活性和可维护性。
反射与工厂模式实现IOC
Spring 中的IoC 的实现原理就是工厂模式加反射机制。我们首先看一下不用反射机
制时的工厂模式:
interface fruit { public abstract void eat(); } class Apple implements fruit{ public void eat(){ System.out.println("Apple"); } } class Orange implements fruit{ public void eat(){ System.out.println("Orange"); } }
//也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
class Factory{ public static fruit getInstance(String fruitName){ fruit f=null; if("Apple".equals(fruitName)){ f=new Apple(); } if("Orange".equals(fruitName)){ f=new Orange(); } return f; } } class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Orange"); f.eat(); } }
上面写法的缺点是当我们再添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改动就会很多。
下面用反射机制实现工厂模式:
interface fruit { public abstract void eat(); } class Apple implements fruit{ public void eat(){ System.out.println("Apple"); } } class Orange implements fruit{ public void eat(){ System.out.println("Orange"); } } class Factory{ public static fruit getInstance(String ClassName){ fruit f=null; try{ f=(fruit)Class.forName(ClassName).newInstance(); }catch (Exception e) { e.printStackTrace(); } return f; } } class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Reflect.Apple"); if(f!=null){ f.eat(); } } }
总结:
现在就算我们添加任意多个子类的时候,工厂类都不需要修改。使用反射机制实现的工
厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道
一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。