JAVA反射实例详解与介绍

来源:互联网 发布:js中事件的概念 编辑:程序博客网 时间:2024/06/05 17:06

我们都知道Java反射很重要,这次我来抛个砖头奋斗!!!


一:反射

     反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。

  使用java的反射,一般有下面三步:

    1:获得你想操作类的Class对象

    2:通过第一步获得的Class对象去取得操作类的方法或是属性名

    3:操作第二步取得的方法或是属性

二:例子

    Java的反射机制中类有Class对应,类的方法有Method对应,当然属性也有Field与之对应。

2.1 通过反射获取当前类和父类的相关属性

public class GetOtherClassFiled {      public static void main(String[] args) throws ClassNotFoundException {          Class<?> demo = Class.forName("com.tanjie.reflect.Persons");          System.out.println("获取当前类的所有属性:=========================");          Field field[] = demo.getDeclaredFields();          for(int i=0;i<field.length;i++){              int mo = field[i].getModifiers();              //修饰符              String prev = Modifier.toString(mo);              //属性类型              Class<?> type = field[i].getType();              System.out.println(prev + " " + type.getName() + " " + field[i].getName());          }          System.out.println("实现的父类接口属性:============================");          Field field2[] = demo.getFields();          for(int j=0;j<field2.length;j++){              int mo = field2[j].getModifiers();              String prev = Modifier.toString(mo);              Class<?> type = field2[j].getType();              System.out.println(prev + " " + type.getName() + " " + field2[j].getName());          }       }    } 
   运行结果:

获取当前类的所有属性:=========================  private java.lang.String name  实现的父类接口属性:============================  public static final java.lang.String name
 2.2 获取类的相关属性,构造函数,接口

public class ClassImplesWhichInterface {        public static void main(String[] args) throws Exception {          Class<?> demo = Class.forName("com.tanjie.reflect.Persons");           //获取接口类           Class<?> interfaces[] = demo.getInterfaces();          //获取父类           Class<?> parents = demo.getSuperclass();           //获取所有的构造函数           Constructor<?> constructors[] = demo.getConstructors();           for (int i = 0; i < interfaces.length; i++) {               System.out.println("实现了哪些接口类:" + interfaces[i].getName());           }           for (int i = 0; i < constructors.length; i++) {               System.out.println("类有哪些构造函数:" + constructors[i]);           }           System.out.println("继承的父类:" + parents.getName());           for (int i = 0; i < constructors.length; i++) {             Class<?> paramenter[] = constructors[i].getParameterTypes();             int mo = constructors[i].getModifiers();             System.out.println(Modifier.toString(mo) + " " + constructors[i].getName());             for(int j=0;j<paramenter.length;j++){                 System.out.println(paramenter[j].getName());            }            }         }  }

运行结果:

实现了哪些接口类:com.tanjie.reflect.Parents  类有哪些构造函数:public com.tanjie.reflect.Persons()  类有哪些构造函数:public com.tanjie.reflect.Persons(java.lang.String)  继承的父类:java.lang.Object  public com.tanjie.reflect.Persons  public com.tanjie.reflect.Persons  java.lang.String


三:实际应用

       上面2个列子我们熟悉了反射常用的方式,记不住的时候,翻翻api就会使用了,反射对应的方法都简单明了,下面我们来看一个具体在项目中利用反射的例子。

  假如我们有这样一个需求,在你的程序中,常常有一些定义错误码的枚举类,而错误编码怎样才能保证不会被重复定义呢,如果每次定义的时候都去手动检查一下肯定是非常麻烦的,我们可以利用反射来实现动态的错误码检测

 3.1 定义一个注解类

@Retention(RetentionPolicy.RUNTIME)  @Target(ElementType.TYPE)  public @interface EnumTag {    String name();  }  

RetentionPolicy.RUNTIME:表示在源码,编译后的.class都保存信息,在执行的时候也会把这些信息加载到JVM中。
  @Target里面的ElementType是用来制定Annotation可以用在那一种类型。

  3.2 定义枚举类  

@EnumTag(name = "errorEnum")  public enum ErrorEnum {            JAVA_TIME_OUT(1000),            ZOOKEEPER_TIME_OUT(2000);        private final int errorCode;        private final String errMessage;        /**      * 枚举类构造函数,初识化      *       * @param errorCode      *            errorCode      */      private ErrorEnum(int errorCode) {          this.errorCode = errorCode;          this.errMessage = "System Error";      }        public int getErrorCode() {          return errorCode;      }        public String getErrMessage() {          return errMessage;      }        public static List<Integer> getErrorCodes() {          List<Integer> errorCodeList = new ArrayList<Integer>();          for (final ErrorEnum em : ErrorEnum.values()) {              int code = em.getErrorCode();              errorCodeList.add(code);          }          return errorCodeList;      }  }  

   3.3 定义bean

public class ValidateEnumMark implements InitializingBean {        private List<Integer> errorList;        public ValidateEnumMark() {          errorList = new ArrayList<Integer>();      }        /**      *       * 在初始化之前做的事情通过@PostConstruct和 @PreDestroy方法实现初始化和销毁bean之前进行的操作      *       * @throws SecurityException      * @throws NoSuchMethodException      * @throws InvocationTargetException      * @throws IllegalArgumentException      * @throws IllegalAccessException      *      */      @SuppressWarnings("unchecked")      @PostConstruct      public void validate() throws NoSuchMethodException, SecurityException,              IllegalAccessException, IllegalArgumentException,              InvocationTargetException {          Reflections reflections = new Reflections(                  "com.tanjie.reflect.application");          Set<Class<?>> sets = reflections.getTypesAnnotatedWith(EnumTag.class);          for (Class<?> demo : sets) {              // 通过反射获取指定方法              Method method = demo.getDeclaredMethod("getErrorCodes",                      new Class[] {});              // 通过反射调用其它类的方法              List<Integer> list = (List<Integer>) method.invoke(demo,                      new Object[] {});              if (null != list && !list.isEmpty()) {                  for (Integer integer : list) {                      if (errorList.contains(integer)) {                          System.out.println("错误编码重复");                      } else {                          errorList.add(integer);                      }                  }              }          }                  System.out.println("目前服务中定义的错误码有:" + errorList);      }        @Override      public void afterPropertiesSet() throws Exception {          System.out.println("校验完成.....");      }  }
   在spring的配置文件里面

<context:annotation-config /><context:component-scan base-package="com.tanjie.reflect.application"/>  <!-- 在加载所有的配置文件之前,检测错误码是否重复 -->  <bean id="validateErrorMessageExecutor"      class="com.tanjie.reflect.application.ValidateEnumMark" />

 完成上面的配置后,spring容器在启动时,首先就会检测你整个程序中是否存在重复定义的错误码了。

4:反射的性能

       反射不太好的地方就是性能了,因为通过反射来获取字段或者方法比直接使用java代码要慢很多,但是这也得看反射用在什么地方,在一个大项目中,如果反射仅仅用在无关紧要的,不影响性能的地方,那么这点性能的丢失也就无关紧要了。






0 0