1.什么是 反射!
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。反射通常具有以下用途:
1.使用Assembly定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
2.使用Module了解如下的类似信息:包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
3.使用ConstructorInfo了解如下的类似信息:构造函数的名称、参数、访问修饰符(如public或private)和实现详细信息(如abstract或virtual)等。
4.使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
5.使用MethodInfo来了解如下的类似信息:方法的名称、返回类型、参数、访问修饰符(如public或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
6.使用FieldInfo来了解如下的类似信息:字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等;并获取或设置字段值。
7.使用EventInfo来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
8.使用PropertyInfo来了解如下的类似信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。
9.使用ParameterInfo来了解如下的类似信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。
2.反射的常用方法!
2.Field类:代表类的成员变量(成员变量也称为类的属性)。
3.Method类:代表类的方法。
4.Constructor类:代表类的构造方法。
5.Array类:提供了动态创建数组,以及访问数组元素的静态方法。
◆.Class类
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
getConstrutors():获得类的public类型的构造方法。
getConstrutor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
Field fields[]=classType.getDeclaredFields();
以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
for(int i=0; i Field field=fields[i];
String fieldName=field.getName();
String firstLetter=fieldName.substring(0,1).toUpperCase();
//获得和属性对应的getXXX()方法的名字 String getMethodName="get"+firstLetter+fieldName.substring(1);
//获得和属性对应的setXXX()方法的名字 String setMethodName="set"+firstLetter+fieldName.substring(1);
//获得和属性对应的getXXX()方法
Method getMethod=classType.getMethod(getMethodName,new Class[]{});
//获得和属性对应的setXXX()方法
Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()});
//调用原对象的getXXX()方法
Object value=getMethod.invoke(object,new Object[]{});
System.out.println(fieldName+":"+value);
//调用复制对象的setXXX()方法
setMethod.invoke(objectCopy,new Object[]{value});}
invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。
反射在应用中大多会与配置文件、特性等元素联系起来,接下来我们来看一些配置节点片段代码。
配置节点一 <httpModules> <add name="test" type="MyModule.MyHttpModule,MyHttpModule"/> </httpModules>
配置节点二 <handlers>
<add name="AjaxPro" verb="POST,GET" path="ajaxpro/*.ashx" type="AjaxPro.AjaxHandlerFactory,AjaxPro"/>
</handlers>
这两个配置节点相信大家都不陌生,节点一是为asp.net处理管道流程注册一个自定义处理模块,第二个配置节点是为asp.net特定目录下的某种特定文件注册一种自定义的处理程序,这里的例子是AjaxPro的配置节。对于httpModules和httpHandler理解有偏差的地方欢迎大家指正,我们接着往下。
很多时候对于这样的配置文件我们只知道要这配置,程序运行起来之后也不会去思考一个为什么。这两个add配置节点里面都有一个type = "XXX.XXX,XXXX"的属性,属性值配置的是 "命名空间.类名,程序集名称"。这正好符合我们反射创建一个对象的必要条件,配置节点的值告诉了我们程序集的名称还有类的信息。通常的情况下反射还会和工厂模式结合起来形成反射工厂,asp.net会在应用程序启动时去读取web.config配置文件的信息,并去加载需要的程序集,然后通过反射的方式来创建我们注册的httpModules和httpHandler类型的对象。这样就可以很轻松的在httpModules和httpHandler中实现我们自定义的业务逻辑了。
4.何为注解!注解的常用规范
什么是注解?
–可以附加在package, class, method, field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。
内置注解
–与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:
–@SuppressWarnings("unchecked")
–@SuppressWarnings(value={"unchecked", "deprecation"})
内置注解课堂代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package com.bjsxt.test.annotation; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * 测试内置注解用法 * @author 尚学堂高淇 * */ @SuppressWarnings ( "all" ) public class Demo01 /*extends Object*/ { @Override public String toString(){ return "" ; } @Deprecated public static void test001(){ System.out.println( "test001" ); } public static void test002(){ List list = new ArrayList(); List list2 = new ArrayList(); } public static void main(String[] args) { Date d = new Date(); test001(); } } |
自定义注解
•如果只有一个参数成员,一般参数名为value
元注解
–@Inherited
@Target
@Retention
自定义注解课堂代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.bjsxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (value={ElementType.METHOD,ElementType.TYPE}) @Retention (RetentionPolicy.RUNTIME) public @interface SxtAnnotation01 { String studentName() default "" ; int age() default 0 ; int id() default - 1 ; //String indexOf("abc") -1 String[] schools() default { "清华大学" , "北京上学堂" }; } |
1
2
3
4
5
6
7
8
9
10
11
12
|
package com.bjsxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (value={ElementType.METHOD,ElementType.TYPE}) @Retention (RetentionPolicy.RUNTIME) public @interface SxtAnnotation02 { String value(); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package com.bjsxt.test.annotation; /** * 测试自定义注解的使用 * */ @SxtAnnotation01 public class Demo02 { @SxtAnnotation01 (age= 19 ,studentName= "老高" ,id= 1001 , schools={ "北京大学" , "北京航空航天大学" }) public void test(){ } @SxtAnnotation02 ( "aaaa" ) public void test2(){ } } |
使用反射机制读取注解信息
上面我们只学习了如何自定义注解、使用注解。我们还需要了解如何解析注解信息,这样才能形成一个完整的闭环。
课堂代码
1
2
3
4
5
6
7
8
9
10
11
12
|
package com.bjsxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (value={ElementType.TYPE}) @Retention (RetentionPolicy.RUNTIME) public @interface SxtTable { String value(); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.bjsxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (value={ElementType.FIELD}) @Retention (RetentionPolicy.RUNTIME) public @interface SxtField { String columnName(); String type(); int length(); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package com.bjsxt.test.annotation; @SxtTable ( "tb_student" ) public class SxtStudent { @SxtField (columnName= "id" ,type= "int" ,length= 10 ) private int id; @SxtField (columnName= "sname" ,type= "varchar" ,length= 10 ) private String studentName; @SxtField (columnName= "age" ,type= "int" ,length= 3 ) private int age; public int getId() { return id; } public void setId( int id) { this .id = id; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this .studentName = studentName; } public int getAge() { return age; } public void setAge( int age) { this .age = age; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package com.bjsxt.test.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** * 使用反射读取注解的信息,模拟处理注解信息的流程 * @author 尚学堂高淇 * */ public class Demo03 { public static void main(String[] args) { try { Class clazz = Class.forName( "com.bjsxt.test.annotation.SxtStudent" ); //获得类的所有有效注解 Annotation[] annotations=clazz.getAnnotations(); for (Annotation a : annotations) { System.out.println(a); } //获得类的指定的注解 SxtTable st = (SxtTable) clazz.getAnnotation(SxtTable. class ); System.out.println(st.value()); //获得类的属性的注解 Field f = clazz.getDeclaredField( "studentName" ); SxtField sxtField = f.getAnnotation(SxtField. class ); System.out.println(sxtField.columnName()+ "--" +sxtField.type()+ "--" +sxtField.length()); //根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表 } catch (Exception e) { e.printStackTrace(); } } } |