加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

Java反射实例介绍

发布时间:2021-12-10 17:17:14 所属栏目:PHP教程 来源:互联网
导读:一:反射 反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。 使用Java的反射,一般有下面三步: 1:获得你想操作类的Class对象 2:通过第一步获得的Class对象去取得操作类的方

一:反射
 
反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。
 
使用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;
 }
}
</SPAN>
 
3.3 定义bean
 
<SPAN style="FONT-SIZE: 18px">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代码要慢很多,但是这也得看反射用在什么地方,在一个大项目中,如果反射仅仅用在无关紧要的,不影响性能的地方,那么这点性能的丢失也就无关紧要了。

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读