反射!

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.反射的常用方法!

在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
1.Class类:代表一个类。
2.Field类:代表类的成员变量(成员变量也称为类的属性)。
3.Method类:代表类的方法。
4.Constructor类:代表类的构造方法。
5.Array类:提供了动态创建数组,以及访问数组元素的静态方法。
◆.Class类
在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。
Class类是Reflection API中的核心类,它有以下方法
(1)获得对象的类型:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
getConstrutors():获得类的public类型的构造方法。
getConstrutor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
(2)通过默认构造方法创建一个新的对象:
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
(3)获得对象的所有属性:
Field fields[]=classType.getDeclaredFields();
 Class类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。
以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
(4)获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性复制到新的对象中:
 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});}
◆.Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。
invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。
 ◆.Array类
java.lang.Array类提供了动态创建和访问数组元素的各种静态方法。如例程10-4所示的ArrayTester1类的main()方法创建了一个长度为10的字符串数组,接着把索引位置为5的元素设为“hello”,然后再读取索引位置为5的元素的值。
import java.lang.reflect.*;
public class ArrayTester1 {
  public static void main(String args[])throws Exception {   
 Class classType = Class.forName("java.lang.String");   
//创建一个长度为10的字符串数组  
  Object array = Array.newInstance(classType, 10);   
 //把索引位置为5的元素设为"hello"  
  Array.set(array, 5, "hello");   
//读取索引位置为5的元素的值   
String s = (String) Array.get(array, 5);    System.out.println(s);  }}
 
3.反射的应用场景

反射在应用中大多会与配置文件、特性等元素联系起来,接下来我们来看一些配置节点片段代码。

配置节点一
<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.何为注解!注解的常用规范

什么是注解?

•Annotation是从JDK5.0开始引入的新技术。
•Annotation的作用:
–不是程序本身,可以对程序作出解释。(这一点,跟注释没什么区别)
–可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别。如果没有注解信息处理流程,则注解毫无意义)
•Annotation的格式:
–注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:@SuppressWarnings(value="unchecked")。
•Annotation在哪里使用?

–可以附加在package, class, method, field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。

内置注解

•@Override
–定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明。
•@Deprecated
–定义在java.lang.Deprecated中,此注释可用于修辞方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。
•@SuppressWarnings
–定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。

–与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:

–@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();
    }
     
     
}

自定义注解

•使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
•要点:
–@interface用来声明一个注解
•格式为:    public @interface 注解名 {定义体}
–其中的每一个方法实际上是声明了一个配置参数。
•方法的名称就是参数的名称
•返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。
•可以通过default来声明参数的默认值。

•如果只有一个参数成员,一般参数名为value

 
• 注意:
–注解元素必须要有值。我们定义注解元素时,经常使用空字符串、0作为默认值。
–也经常使用负数(比如:-1)表示不存在的含义

元注解

•元注解的作用就是负责注解其他注解。 Java定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。
•这些类型和它们所支持的类在java.lang.annotation包中可以找到
–@Target
–@Retention
–@Documented

–@Inherited

 

@Target

–作用:
•用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

 
–@Target(value=ElementType.TYPE)

@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();
        }
         
    }
}
 
 
 
 
原文地址:https://www.cnblogs.com/kldsw/p/5579528.html