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代码要慢很多,但是这也得看反射用在什么地方,在一个大项目中,如果反射仅仅用在无关紧要的,不影响性能的地方,那么这点性能的丢失也就无关紧要了。 ![]() (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |