反射总结
反射创建对象 操作字段 调用方法 的异同
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
这篇日志着重阐述反射创建对象,操作字段和调用方法的步骤和形式的特点
1. 反射 Constructor, Field, Method 步骤
无论是通过Java反射 创建对象,操作字段还是调用方法,获取与相关类关联Class对象的必不可少的一步
(1). 获取Class对象
[1].获取Class对象的步骤 (1次关联)
通过以字符串形式给出的全类名 ===>获取相关类的Class对象
[2]. 常用的方法就是Class的静态方法forName ( )方法
【特点】在反射中以字符串形式出现全类名关联到Class对象上以后,相关类类名就不会出现在后续的反射代码中。
【举例】
Class clazz = Class.forName("cn.itcast.bean.Person");
//此后的代码中,Person就不会显示地出现在代码中。
(2). 通过Class对象创建相关类对象的步骤
[1]. 执行基础
建立在获取到Class对象的基础之上
[2]. 通过反射创建对象的步骤 (2次关联)
step1:调用Class对象的getConstructor(Class<?>... parameterTypes)方法
并
关联要调用的构造函数的形式参数列表[第1次关联] ====> 来获取指定形参的构造函数类Constructor的对象
【注意】这里不用关联构造方法的名字,因为构造方法的名字和类名相同。全类名已经在获取Class对象的时候关联进去了。
【注意】关联构造函数的形式参数的原因就是构造函数存在重载,仅仅通过构造函数名称无法得知哪一个构造函数被调用。
【举例】
Constructor constructor =
clazz.getConstructor(String.class,int.class);
//注意到getConstructor(Class<?>... parameterTypes)仅仅需要形参列表的数据,//而不需要构造方法的名字
//相当于要调用publicPerson(String name, int age){…}这个构造方法
step2:调用Constructor对象的newInstance(Object…initArgs)方法
并
关联和要调用的构造方法的形式参数相对应的实际参数[第2次关联]
【举例】
Object obj =constructor.newInstance("Benjamin", 28);
//"Benjamin" 对应 String.class
//28 对应 int.class
[2]. 【特点】2次关联:关联构造函数的形式参数(1次) 和实际参数 (1次)。不用关联构造方法名称
(3). 通过Class对象操作相关类对象的字段步骤
[1]. 执行基础
建立在获取到Class对象 +通过反射创建出来的相关类的对象的基础之上
[2]. 通过反射操作相关字段的步骤 (2次关联)
step1:调用Class对象的getField(String name)方法
并
关联要操作的以字符串形式给出的成员字段的名字[第1次关联]====> 来获取指定字段对应的类Field的对象
【特点】在反射中以字符串形式出现字段名关联到Field类对象上以后,相关字段名就不会出现在后续的反射代码中。
【举例】
Field field =clazz.getField("country");
//field对象就和country字段相关联,操作field这个对象就相当于对country这个字段进行//操作 此后的代码中,country就不会显示地出在代码中
step2:调用Field对象的set(Object obj, Object value)方法或get(Object obj)
方法 【对字段的操作只有获取和设置两个动作】
并
关联和字段名对应的字段值 +对应字段所属的对象【set】或关联和对应字段所属的对象【get】[第2次关联]
【注意】因为操作字段的方法都是setter或者getter。这个时候,Field本身也具备set( )方法或者get( )方法,所以Field知道调用哪个方法来操作字段。所以不用关联操作字段的方法名。
【举例】
field.set(obj, "China");
//设置field中关联的country字段,值为China---set
Object o =field.get(obj);
//获取field中关联的country字段的值 –--------get
(4). 通过Class对象调用相关类对象的方法步骤
[1]. 执行基础
建立在获取到Class对象 +通过反射创建出来的相关类的对象的基础之上
[2]. 通过反射调用相关方法的步骤 (2次关联)
step1:调用Class对象的getMethod(String name, Class<?>… parameterTypes)方法
并
关联要操作的以字符串形式给出的成员方法的名字和成员方法的形式参数列表[第1次关联]====> 来获取指定方法对应的类Method的对象
【特点】在反射中以字符串形式出现方法名关联到Method类对象上以后,相关字段名就不会出现在后续的反射代码中。
【举例】
Method method =
clazz.getMethod("paramMethod", String.class,int.class);
//相当于要调用public voidparamMethod(String name, int age){…}这个成员方法
step2:调用Method对象的invoke(Object obj, Object…parameterTypes)方法
并
关联和要调用的构造方法的形式参数相对应的实际参数+对应字段所属的对象 [第2次关联]
【举例】
method.invoke(obj, "Benjamin", 110);
//"Benjamin" 对应 String.class
//110 对应 int.class
2). 执行步骤的相似性
(1). Class, Constructor, Field和Method执行步骤的图例
(2). 执行步骤的相似性
[1]. 一旦以字符串进行关联之后,相应的字符串中元素在代码中就不会再次体现,会被封装到对应的对象中。【Constructor类对象没有这一步】
【举例】
{1}. Class:Class clazz =Class.forName("cn.itcast.bean.Person");
之后Person不会显式写到代码中,被Class对象封装
{2}. Field:Field field=clazz.getField("country");
之后setCountry或者getCountry这样对country字段操作的方法不会有country体现。取而代之的是Field的set和get方法来做操作。
{3}. Method:Method method=clazz.getDeclaredMethod("showII",null);
之后不会出现xxx.showII( ) 这样的代码,直接被Method对象所封装。
[2]. 反射基本操作就是把传统的操作拆分开来,格式化传统的操作,有利于搭建框架技术。
e.g.
{1}. 以传统的创建对象为例本来是 Person p =new Person(“Benjamin”,28); 但是这样的代码没有扩展性,换做Student类,又要重写为 Student s =new Student(“Benjamin”, 28);这种代码无法统一。
现在使用反射来构建:
Class clazz =Class.forName(“cn.itcast.bean.Person”);
Constructor con=clazz.getConstructor(String.class, int.class);
Object obj =con.newInstance(“Benjamin”,28);
虽然原来一步的代码变成了三步,但是现在只要是为forName方法传入不同字符串,就能创建不同的对象。以上代码如果传入“cn.itcast.bean.Student”, 就能创建Student实例对象。
【结论】
{1}. 传统代码虽然使用起来简洁,但是把更多的和特定类名,特定字段名或者特定方法名相关的元素以非参数的形式写死到代码中,没有办法扩充。
{2}. 反射代码虽然使用起来相对麻烦,但是他将很多和特定元素相关的非参数代码统一成String类型并进行参数化,使得通用性大幅度提高,为框架技术奠定了坚实的基础。
[2]. 关联元素
{1}. 最标准的关联格式【双关联】就是:
(1). 关联1:调用的方法名+形参
(2). 关联2:调用的实参+操作所属的对象
【简化】由于构造方法和字段有特殊的地方,所以以上的双关联格式有所简化。
{2}. Constructor的简化
{2}1. 由于构造方法和类名一致,类名被封装到Class对象中。所以Constructor在第一关联的部分就省去了对“方法名”的关联。
{2}2. 由于构造函数是用来创建对象的,不需要被某个对象调用,所以第二关联省去对“操作所属的对象”的关联。
【举例】
//关联形参,但没有方法名
Constructor constructor =clazz.getConstructor(String.class,int.class);
//关联实参,但没有对应对象
Object obj =constructor.newInstance("Benjamin", 28);
{3}. Field的简化
{3}1. 由于字段没有什么参数,所以第一关联省去对“形参”的关联。
其中对“方法名”的关联,对于Field仅仅做了一半。由于字段的setter和getter命名是setFieldName(xxx)和getFieldName()。所以只要是给出了字段名,setter和getter的名字就能构建出来。这样,对于不同类的不同字段FieldName被定义成String类型相关联,通用的set和get就被设置为Field的方法。
所以这里名义上是关联字段名,实际上是关联的方法名
【举例】
//关联方法名的一半,另一半封装到field对象中 没有对形式参数进行关联
Field field =clazz.getField("country");
//setter操作
field.set(obj, "China");
//getter操作
Object o =field.get(obj);
{3}. Method的不能简化。因为Method是没有特殊的地方,所以遵循完整的双关联格式。
2. 反射代码书写 形式上的特点
反射含义的代码字面理解
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------