黑马程序员-JAVA-反射的一些特殊例子
2015-04-14 09:46
627 查看
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
上次已经稍稍了解过了反射的基本用法,那么在一些特殊的情况下,应该怎么取得对象的反射,又有何不同之处呢。
下面分别做一些简单的小例子来测试一下:
其中一些方法已经抽象提取,文章最后附其代码,这里是反射中用到的类以及接口,注解如下:
输出如下:
可以看出,除非能够明确获得一个实现接口的实例,否则无法使用任何实例字段和方法,静态的没有问题。还有通过反射,可以证明:接口是没有构造方法的,当然也无法通过.newInstance()产生实例。
输出如下:
可以看到注解在反射输出中与接口别无二致,但是可以通过isAnnotation()方法来判断是否注解以及使用isAnnotationPresent来判断当前元素是否存在注解。
代码如下:
输出结果:
无论是内部类还是静态内部类,或者内部定义注解,都能成功取得他们的信息并且成功创建实例来访问字段和方法。但是有一个问题,匿名内部类的信息不在getDeclaredClasses之中。
传入Outer.class的测试结果:
前辈的方法果然有效,匿名内部类也无所遁形了。
这里是刚才调用到的几个遍历方法,字段,注解,构造方法的代码,以及一个小小的输出控制台代码
上次已经稍稍了解过了反射的基本用法,那么在一些特殊的情况下,应该怎么取得对象的反射,又有何不同之处呢。
下面分别做一些简单的小例子来测试一下:
其中一些方法已经抽象提取,文章最后附其代码,这里是反射中用到的类以及接口,注解如下:
interface ITest { final int val=87; void todo(); int getnum(String val); default int getsum(String val) { return this.getnum(val) + 0xff; } static double getPI(){ return Math.PI; } } class Outer{ @Anno(comm="Inner Class") private class Inner implements ITest{ final int val=987; @Override public void todo(){ return; } @Override public int getnum(String val){ return val.length(); } } @Anno(comm="Static Inner Class") private static class StaticInner{ final int sval=877; public void todo(){ return; } int getnum(String val){ return val.length(); } } @Annos({@Anno(comm="void func"),@Anno(comm="with AnonymousInnerClass")}) private void fun(){ new ITest(){ @Override public void todo() { return; } @Override public int getnum(String val) { return 0; } }; return; } @Repeatable(value = Annos.class) @Retention(RetentionPolicy.RUNTIME) @interface Anno{ String comm() default "rA"; } @Retention(RetentionPolicy.RUNTIME) static @interface Annos { Anno[] value(); } }
接口的反射
接口是不能取得实例的,那么getClass()这一途径就无效了。private static void testInterface() { Class<?> ci = ITest.class; sp(ci); showAnnotations(ci); sp(); testConstructor(ci); showFields(ci); testMethods(ci); }
输出如下:
interface com.itheima.ITest Constructors Reflect Test: .newInstance() Test: unable to init newInstance no Constructors Field Reflect Test: public static final int com.itheima.ITest.val Value:87 Method Reflect Test: public abstract void com.itheima.ITest.todo() unable to invoke instance method by null Object public default int com.itheima.ITest.getsum(java.lang.String) unable to invoke instance method by null Object public abstract int com.itheima.ITest.getnum(java.lang.String) unable to invoke instance method by null Object public static double com.itheima.ITest.getPI() result:3.141592653589793
可以看出,除非能够明确获得一个实现接口的实例,否则无法使用任何实例字段和方法,静态的没有问题。还有通过反射,可以证明:接口是没有构造方法的,当然也无法通过.newInstance()产生实例。
注解的反射
注解的简单反射例子如下:Class<?> ci = Outer.class; sp(ci); showAnnotations(ci); sp(); Class<?>[] inners=ci.getDeclaredClasses(); for (Class<?> cls : inners) { sp(cls); showAnnotations(cls); sp(); } Method[] methods = ci.getDeclaredMethods(); if (methods.length == 0) { sp("no Methods"); } for (Method method : methods) { sp(method.toGenericString()); showAnnotations(method); } sp();
输出如下:
class com.itheima.Outer interface com.itheima.Outer$Anno Annotation[@java.lang.annotation.Repeatable(value=interface com.itheima.Outer$An nos):@java.lang.annotation.Retention(value=RUNTIME)] interface com.itheima.Outer$Annos Annotation[@java.lang.annotation.Retention(value=RUNTIME)] class com.itheima.Outer$Inner Annotation[@com.itheima.Outer$Anno(comm=Inner Class)] class com.itheima.Outer$StaticInner Annotation[@com.itheima.Outer$Anno(comm=Static Inner Class)] private void com.itheima.Outer.fun() Annotation[@com.itheima.Outer$Annos(value=[@com.itheima.Outer$Anno(comm=void fun c), @com.itheima.Outer$Anno(comm=with AnonymousInnerClass)])]
可以看到注解在反射输出中与接口别无二致,但是可以通过isAnnotation()方法来判断是否注解以及使用isAnnotationPresent来判断当前元素是否存在注解。
内部类和静态内部类的反射
其实刚才的例子已经使用了内部类了,这里改写一下代码输出更详细的信息代码如下:
private static void testInnerClass() { Class<?> ci = Outer.class; sp(ci); sp(); Class<?>[] inners=ci.getDeclaredClasses(); for (Class<?> cls : inners) { sp(cls); showAnnotations(cls); sp(); testConstructor(ci); showFields(ci); testMethods(ci); } }
输出结果:
class com.itheima.Outer interface com.itheima.Outer$Anno Annotation[@java.lang.annotation.Repeatable(value=interface com.itheima.Outer$An nos):@java.lang.annotation.Retention(value=RUNTIME)] Constructors Reflect Test: .newInstance() Test: get new instance:com.itheima.Outer@4554617c com.itheima.Outer() constructed new instance:com.itheima.Outer@74a14482 Field Reflect Test: Method Reflect Test: private void com.itheima.Outer.fun() Annotation[@com.itheima.Outer$Annos(value=[@com.itheima.Outer$Anno(comm=void fun c), @com.itheima.Outer$Anno(comm=with AnonymousInnerClass)])] interface com.itheima.Outer$Annos Annotation[@java.lang.annotation.Retention(value=RUNTIME)] Constructors Reflect Test: .newInstance() Test: get new instance:com.itheima.Outer@135fbaa4 com.itheima.Outer() constructed new instance:com.itheima.Outer@45ee12a7 Field Reflect Test: Method Reflect Test: private void com.itheima.Outer.fun() Annotation[@com.itheima.Outer$Annos(value=[@com.itheima.Outer$Anno(comm=void fun c), @com.itheima.Outer$Anno(comm=with AnonymousInnerClass)])] class com.itheima.Outer$Inner Annotation[@com.itheima.Outer$Anno(comm=Inner Class)] Constructors Reflect Test: .newInstance() Test: get new instance:com.itheima.Outer@330bedb4 com.itheima.Outer() constructed new instance:com.itheima.Outer@2503dbd3 Field Reflect Test: Method Reflect Test: private void com.itheima.Outer.fun() Annotation[@com.itheima.Outer$Annos(value=[@com.itheima.Outer$Anno(comm=void fun c), @com.itheima.Outer$Anno(comm=with AnonymousInnerClass)])] class com.itheima.Outer$StaticInner Annotation[@com.itheima.Outer$Anno(comm=Static Inner Class)] Constructors Reflect Test: .newInstance() Test: get new instance:com.itheima.Outer@4b67cf4d com.itheima.Outer() constructed new instance:com.itheima.Outer@7ea987ac Field Reflect Test: Method Reflect Test: private void com.itheima.Outer.fun() Annotation[@com.itheima.Outer$Annos(value=[@com.itheima.Outer$Anno(comm=void fun c), @com.itheima.Outer$Anno(comm=with AnonymousInnerClass)])]
无论是内部类还是静态内部类,或者内部定义注解,都能成功取得他们的信息并且成功创建实例来访问字段和方法。但是有一个问题,匿名内部类的信息不在getDeclaredClasses之中。
匿名内部类的反射
如何反射匿名内部类,为此特地搜索了一下,果断发现有前辈利用编译器命名规则来去匿名内部类的方法。毫不犹疑,试试看:private static void testAnonymousInnerClass(Class outer) { String outerName=outer.getCanonicalName(); Class<?> ci = null; //尝试10次,如果需要可以尝试更多 for (int i = 0; i < 10; i++) { ci=null; try { ci=Class.forName(outerName+"$"+i); } catch (ClassNotFoundException e) { //fail continue; } if(ci!=null&&ci.isAnonymousClass()){ sp(ci); showAnnotations(ci); sp(); testConstructor(ci); showFields(ci); testMethods(ci); } } }
传入Outer.class的测试结果:
class com.itheima.Outer$1 Constructors Reflect Test: .newInstance() Test: unable to init newInstance com.itheima.Outer$1(com.itheima.Outer) constructed new instance:com.itheima.Outer$1@2a139a55 com.itheima.Outer$1 Field Reflect Test: final com.itheima.Outer com.itheima.Outer$1.this$0 Value:com.itheima.Outer@6d06d69c com.itheima.Outer$1 Method Reflect Test: public void com.itheima.Outer$1.todo() public int com.itheima.Outer$1.getnum(java.lang.String) result:0
前辈的方法果然有效,匿名内部类也无所遁形了。
这里是刚才调用到的几个遍历方法,字段,注解,构造方法的代码,以及一个小小的输出控制台代码
public static void showAnnotations(AnnotatedElement e) { Annotation[] annotations = e.getAnnotations(); if (annotations.length > 0) { sp(annotations); } } public static void showFields(Class<?> ci) { // get an instance for Fields Object instance = tryGetInstance(ci); Field[] flds=ci.getDeclaredFields(); sp("Field Reflect Test:"); for (Field field : flds) { Object result=null; sp(field.toGenericString()) d6dc ; if (!field.isAccessible()) { field.setAccessible(true); } try { result=field.get(instance); System.out.print("Value:"); sp(result); } catch (IllegalArgumentException | IllegalAccessException e) { sp("unable to get value"); } } sp(); } /** * 测试ci类的所有方法 * 参数使用@defaultValue * 实例对象使用@tryGetInstance 为null时不尝试实例对象方法 * 输出到控制台 * @param ci 要测试的类 */ public static void testMethods(Class<?> ci) { // get an instance for Methods Object instance = tryGetInstance(ci); // get methods Method[] methods = ci.getDeclaredMethods(); // test static Methods sp("Method Reflect Test:"); if (methods.length == 0) { sp("no Methods"); } for (Method method : methods) { sp(method.toGenericString()); showAnnotations(method); // Class<?>[] exceptionTypes = method.getExceptionTypes(); // if (exceptionTypes.length > 0) { // sp(exceptionTypes); // } if (isStatic(method)) { tryInvoke(method, null); } else if (instance != null) { tryInvoke(method, instance); } else { sp("unable to invoke instance method by null Object"); } } sp(); } /** * 测试这个类的构造方法 包括使用Class.newInstance() 尝试反射调用无参数构造方法 * 尝试反射调用所有构造方法,其参数值使用@defaultValue(Class) * * @param ci * 测试的类 */ public static void testConstructor(Class<?> ci) { sp("Constructors Reflect Test:"); // Class .newInstance sp(".newInstance() Test:"); try { Object o = ci.newInstance(); sp("get new instance:"+o); } catch (InstantiationException | IllegalAccessException e) { sp("unable to init newInstance"); } // Constructors Reflect: Constructor<?>[] cons = ci.getDeclaredConstructors(); if (cons.length == 0) { sp("no Constructors"); } for (Constructor<?> constructor : cons) { sp(constructor.toGenericString()); Annotation[] annotations = constructor.getAnnotations(); if (annotations.length > 0) { sp(annotations); } // Class<?>[] exceptionTypes = constructor.getExceptionTypes(); // if (exceptionTypes.length > 0) { // sp(exceptionTypes); // } if (!constructor.isAccessible()) { constructor.setAccessible(true); } Parameter[] paras = constructor.getParameters(); Object[] initparas = new Object[paras.length]; for (int i = 0; i < paras.length; i++) { initparas[i] = defaultValue(paras[i].getType()); } try { sp("constructed new instance:" + constructor.newInstance(initparas)); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { sp("unable to construct with default parameters"); } } sp(); } public static boolean isStatic(Method method) { return (method.getModifiers() & Modifier.STATIC) > 0; } /** * 尝试用对象instance来invoke方法method * 方法的参数列表使用@defaultValue生成 * 输出到控制台 * @param method 引发的方法 * @param instance 传入的object 保证其含有method方法 */ public static void tryInvoke(Method method, Object instance) { if (!method.isAccessible()) { method.setAccessible(true); } Parameter[] paras = method.getParameters(); Object[] initparas = new Object[paras.length]; for (int i = 0; i < paras.length; i++) { initparas[i] = defaultValue(paras[i].getType()); } Object result = null; try { result = (method.invoke(instance, initparas)); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { sp("unable to invoke with default parameters"); } if (result != null) { System.out.print("result:"); sp(result); } } /** * 尝试构造一个此类的实例 * 首先尝试.newInstance() * 然后按构造方法声明顺序尝试 * 参数将使用@defaultValue * 一旦成功构造一个实例立即返回 * 失败返回null * @param ci 需要构造的类 * @return ci的实例 */ public static Object tryGetInstance(Class<?> ci) { Object instance = null; try { instance = ci.newInstance(); if (ci.isInstance(instance)) { return instance; } } catch (InstantiationException | IllegalAccessException e) { } Constructor<?>[] cons = ci.getDeclaredConstructors(); if (cons.length == 0) { return null; } for (Constructor<?> constructor : cons) { sp(constructor.getName()); Annotation[] annotations = constructor.getAnnotations(); if (annotations.length > 0) { sp(annotations); } Class<?>[] exceptionTypes = constructor.getExceptionTypes(); if (exceptionTypes.length > 0) { sp(exceptionTypes); } if (!constructor.isAccessible()) { constructor.setAccessible(true); } Parameter[] paras = constructor.getParameters(); Object[] initparas = new Object[paras.length]; for (int i = 0; i < paras.length; i++) { initparas[i] = defaultValue(paras[i].getType()); } try { instance = constructor.newInstance(initparas); if (ci.isInstance(instance)) { return instance; } } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // ignore continue; } } return instance; } /** * 取类的默认值 * 数组返回空数组 * 引用类型全部尝试.newInstance(),异常则返回null * 基本类型中,整形返回0,浮点返回0.0,布尔返回false,void返回null * * @param cls * 类型 * @return 默认值 */ public static Object defaultValue(Class<?> cls) { if (cls.isPrimitive()) { switch (cls.getName()) { case "byte": case "char": case "short": case "int": case "long": return (byte) 0; case "float": case "double": return 0.0f; case "boolean": return false; case "void": return null; } } else if (cls.isArray()) { return Array.newInstance(cls.getComponentType(), 0); } else { try { return cls.newInstance(); } catch (InstantiationException | IllegalAccessException e) { return null; } } return null; } /** * 简单的在控制台输出 对于非数组类型,输出.toString() * 对于数组类型,输出:类型[内容] * 不递归 * @param o * 被打印的对象 */ public static void sp(Object o) { if (o == null) { System.out.println("null"); } if (o.getClass().isArray()) { StringBuilder sb = new StringBuilder(); int len = Array.getLength(o); sb.append(o.getClass().getComponentType().getSimpleName()); if (len == 0) { sb.append("[]"); System.out.println(sb.toString()); return; } sb.append('['); for (int i = 0; i < len; i++) { if (i != 0) { sb.append(':'); } sb.append(Array.get(o, i)); } sb.append(']'); System.out.println(sb.toString()); } else { System.out.println(o); } } public static void sp() { sp(""); }
相关文章推荐
- 黑马程序员——个人对JAVA反射的一些理解
- Java Reflection (JAVA反射) 一些常用例子
- JAVA反射的一些例子
- java基础入门-for循环的一些特殊例子
- java基础入门-for循环的一些特殊例子
- java基础入门-for循环的一些特殊例子
- java反射例子
- 黑马程序员 java之反射
- 黑马程序员_Java基础_高级反射
- 黑马程序员-Java高新技术之反射
- 黑马程序员—Java基础—类的加载和反射
- Java 正则表达式学习总结和一些小例子
- 黑马程序员_java 反射
- 黑马程序员__关于自己的一些学习死角的再学习(基于老毕的java基础视频)
- “黑马程序员”Java反射
- 黑马程序员--反射的一些相关笔记摘要
- 黑马程序员——Java(反射)
- 黑马程序员-Java基础加强-反射
- 黑马程序员-java面向对象的一些问题
- 黑马程序员_JAVA反射学习