反射入门

2017-03-12  本文已影响66人  许先森的许

1、认识反射

“反”,有反就有“正”。正常情况先有类,再产生对象。所谓的反就是可以利用对象找到对象的出处:

在Object类里面提供有一个方法:取得Class对象:

public final Class getClass();

可以输出类的完整名称,就找到了对象的出处。

Class类对象的实例化:

java.lang.Class是一个类。这个类是反射操作的源头,所有的反射都要从此类开始进行。最关键的是这个类有三种实例化方式。

1、调用Object类中的getClass()方法:Class cls = mIntent.getClass();需要实例化对象,需要import导入类

2、使用“类.class”取得:Class cls = Intent.class。不需要实例化对象,需要import导入类

3、调用Class类提供的方法:Class.forName(String className)。不需要import语句导入一个明确的类

反射实例化对象。

当拿到一个类的时候,肯定用关键字new进行对象的实例化操作,但是如果有了Class类对象后,就可以不用New关键字也可以进行对象的实例化操作:

public T newInstance()相当于使用new调用无参构造函数。

有了反射之后,进行实例化的操作不再只是单单依靠关键字new完成了。反射也可以。

所以用反射获取一个对象实例化的步骤为:

1、先获取Class类的实例化对象:Class cls = Class.forName(“xxxxxx”);

2、用Class类的实例化对象获取制定类的实例化对象:Book book=(Book)cls.newInstance();


但是本来用关键字new一行代码就可以完成实例化操作,反射需要两步,这样好吗?


2、理解反射的作用

在任何开发中,一起的耦合都起源于new。

看工程模式。如果想要扩展,就必须改动工厂类中的if else。如果一直扩展,就需要一直修改工厂类。因为工厂类中是通过New产生对象实例的,所以New就是问题的关键。

如果工厂中用反射代替new,就不需要if else和new实例化每个if else中的对象。只需要传入类的完整名称,就可以解耦和。扩展性非常的强!

3、利用反射调用类的结构

a、使用反射调用构造:

之前所说的newInstance()方法实际上等于调用了无参构造函数,但是实际中可能么有无参构造函数,

Class中有方法可以取到构造:public Constructor[]getConstructors():取得全部构造。

和:public Constructor getConstructor(Class… paramterTypes):取得一个指定参数顺序的构造函数。

Constructor类是java.lang.reflect,这时候真正到了反射中。

实例化对象方法public T newInstance(Object… initargs)

所以用反射获取一个没有无参构造函数的类的实例化对象步骤为:

1、先获取Class类对象:Class cls = Class.forName(“xxxxx”);

2、获取指定参数类型顺序的构造函数:Constructor con = cls.getConstructor(Sring.class,double.class);

3、使用获取到的构造函数实例化对象:Object obj = con.newInstance(“第一个参数字符串类型”,10086.8);

所以建议,不管有多少个构造方法,都尽量提供一个无参构造函数,不然太麻烦了。

b、反射调用方法:

Class类中提供了一下方法用来获取类的方法:

public Method[]getMethods()

public Method getMethod(String methodName,Class… paramterTypes)

Method类似java.lang.reflect包下的,其中有个

public Object invoke(Object obj,Object… args)方法。

所以用反射调用方法的步骤为:

1、先获取Class对象:Class cls = Class.forName(“xxxxx”);

并获取对象Object object = cls.newInstance();//必须给出实例化对象

2、获取指定方法:Method setTitleMethod = cls.getMethod(“setTitle”,String.class);

3、调用方法:setTitleMethod.invoke(object,“一本书的标题”);//等价于Book对象.setTitle(“一本书的标题”)

但是这个过程中完全没有出现过Book。也就是说,利用反射可以实现任意类的制定方法的调用。

c、反射调用成员:

类中的属性一定要在本类实例化对象产生后才可以分配内存空间。

Class类中提供了取得成员的方法:

1、取得全部成员:public Field[]getDeclaredFields()

2、取得指定成员:public Field getDeclaredField(String fieldName)

Field是java.lang.reflect包下。其中有:

1、取得属性内容:public Object get(Object obj);

2、设置属性内容:public void set(Object obj,Object value)

所以反射调用成员的步骤为:

假设一个Book类,里面只有一个属性private String title;没有getter/setter方法。

1、先获取Class对象:Class cls = Class.forName(“xxx”);

2、获取对象:Object obj = cls.newInstance();

3、获取指定成员:Field titleField = cls.getDeclaredField(“title”);

4、设置属性内容:titleField.set(obj,“书的名字”);//相当于:Book类对象.title =“书的名字“

但是调用get还是会报错。因为封装性。

这时候需要用到:AccessbleObject

在java.lang.reflect.AccessibleObject类下面(JDK1.8修改):

~ Executable//可执行的

~ Constrictor

~Method

~Field

在这个类中有一个方法:

public void setAccessible(boolean flag)设置是否封装,

设置为false后,就是取消封装,这个时候再调用刚才的get就可以正常调用了。

构造方法和普通方法一样可以取消封装,只不过很少这样去做,而且对属性的访问还是应该是getter和setter方法完成。

学习完这些,反射算是入门了。

上一篇 下一篇

猜你喜欢

热点阅读