• JDK1.7新特性(4):java语言动态性之反射API


    直接通过一个代码示例来熟悉java中通过反射来对构造函数/域以及方法处理的相关API:

      1 package com.rampage.jdk7.chapter2;
      2 
      3 import java.lang.reflect.Array;
      4 import java.lang.reflect.Constructor;
      5 import java.lang.reflect.Field;
      6 import java.lang.reflect.InvocationTargetException;
      7 import java.lang.reflect.Method;
      8 
      9 import com.rampage.jdk7.chapter2.NonStaticNestedClass.NestedClass;
     10 
     11 /**
     12  * 这是java反射API的程序代码示例,其中包括java7以及java7之前的一些API
     13  * @author zyq
     14  *
     15  */
     16 public class ReflectionAPI {
     17     public static void main(String[] args) throws Exception {
     18         ReflectionAPI api = new ReflectionAPI();
     19         api.testConstructors();
     20         api.testFields();
     21         api.testMethods();
     22         api.testArrays();
     23     }
     24     
     25     /**
     26      * 使用java.lang.reflect.Array来操作和创建数组
     27      */
     28     private void testArrays() {
     29         // 这个包下的Array类提供了一个newInstance方法来创建新的数组,第一个参数是数组中的元素类型,后面的参数是数组的维度信息
     30         // 创建一个String类型的长度为10的数组
     31         String[] names = (String[]) Array.newInstance(String.class, 10);
     32         names[0] = "KiDe";
     33         // 设置数组中下标为1的元素的值
     34         Array.set(names, 1, "Kid");
     35         
     36         // 创建两个三维数组
     37         int[][][] matrix1 = (int[][][]) Array.newInstance(int.class, 3, 3, 3);
     38         matrix1[0][0][0] = 12;
     39         int[][][] matrix2 = (int[][][]) Array.newInstance(int[].class, 3, 4);  // 这个其实也是三维数组,因为数组的类型是int[]
     40         matrix2[0][0][0] = 11;
     41         matrix2[0][1] = new int[3];
     42         
     43         
     44     }
     45 
     46     /**
     47      * 反射获取构造方法的测试例子
     48      */
     49     @SuppressWarnings("unchecked")
     50     private void testConstructors() {
     51         try {
     52             // Part1: 测试getConstructors方法,直接调用该方法,不会返回父类的构造方法。只会返回当前类的public类型的构造函数。
     53             Constructor<Child>[] childConstructors = (Constructor<Child>[]) Child.class.getConstructors();
     54             /**
     55              * 输出为:
     56                com.rampage.jdk7.chapter2.Child
     57                [Ljava.lang.reflect.Parameter;@15db9742
     58                1
     59              */
     60             for (Constructor<Child> constructor : childConstructors) {
     61                 System.out.println(constructor.getName());
     62                 System.out.println(constructor.getParameters());
     63                 System.out.println(constructor.getParameterCount());
     64             }
     65             
     66             Constructor<Parent>[] parentConstructors = (Constructor<Parent>[]) Parent.class.getConstructors();
     67             /**
     68              * 输出为:
     69                com.rampage.jdk7.chapter2.Parent
     70                [Ljava.lang.Class;@6d06d69c
     71                1
     72                com.rampage.jdk7.chapter2.Parent
     73                [Ljava.lang.Class;@7852e922
     74                0
     75               发现其实不管该构造函数是否有参数getParameterTypes或者getParameters都会返回值
     76              */
     77             for (Constructor<Parent> constructor : parentConstructors) {
     78                 System.out.println(constructor.getName());
     79                 System.out.println(constructor.getParameterTypes());
     80                 System.out.println(constructor.getParameterCount());
     81             }
     82             Parent.class.getConstructor();
     83             Parent.class.getConstructor(double.class);
     84             // Parent.class.getConstructor(void.class);   会抛出异常,当构造函数没有参数的时候直接不传即可,而不能传void.class
     85             // Parent.class.getConstructor(int.class);    会抛出异常,因为以int为参数的构造函数是不存在的
     86         
     87             // Part2: 测试getDeclaredConstruct,该方法能够得到当前类的所有构造函数,不管是public/protected还是private。
     88             childConstructors = (Constructor<Child>[]) Child.class.getDeclaredConstructors();
     89             /**
     90              * 输出为:
     91                  com.rampage.jdk7.chapter2.Child
     92                 [Ljava.lang.reflect.Parameter;@4e25154f
     93                 1
     94                 com.rampage.jdk7.chapter2.Child
     95                 [Ljava.lang.reflect.Parameter;@70dea4e
     96                 1
     97              */
     98             for (Constructor<Child> constructor : childConstructors) {
     99                 System.out.println(constructor.getName());
    100                 System.out.println(constructor.getParameters());
    101                 System.out.println(constructor.getParameterCount());
    102                 // 私有的构造函数实例化对象的时候需要先调用 setAccessible(true),否则会报权限错误。
    103             }
    104             
    105             // Part3: 参数长度可变的构造函数
    106             // 获取构造函数的时候指定构造函数的参数应当当作数组来指定
    107             Constructor<VaragsConstructor> constructor = VaragsConstructor.class.getDeclaredConstructor(int[].class);
    108             System.out.println(constructor.getName());        // com.rampage.jdk7.chapter2.VaragsConstructor
    109             // 利用得到的Constructor创建对象的实例时,可以把传入的参数转换成Object类型,也可以使用参数类型的数组
    110             VaragsConstructor obj = constructor.newInstance((Object) (new int[] {1, 2, 3, 4}));
    111             obj = constructor.newInstance(new int[] {1, 2, 3, 4});
    112             
    113             // Part4: 嵌套类的构造方法
    114             // 嵌套类需要区分静态嵌套类和非静态嵌套类,对于静态嵌套类,获得其构造函数的方法和其他的非嵌套类没有区别,对于非静态的嵌套类,
    115             // 因为必须先初始化外部类才能使用非静态的嵌套类, 因此在获取构造函数以及使用得到的构造函数实例化对象的时候第一个参数必须是外部类class和外部类实例
    116             Constructor<NestedClass> constructor2 = NestedClass.class.getDeclaredConstructor(NonStaticNestedClass.class, int.class);
    117             NonStaticNestedClass object = new NonStaticNestedClass();
    118             constructor2.newInstance(object, 12);
    119         } catch (ReflectiveOperationException e) {  // 在java6中各种反射的异常需要逐个捕获。而java7提供了一个新的异常类: ReflectiveOperationException,该类可以捕获所有反射操作的异常(因为他是所有反射操作异常的父类) 
    120             System.out.println(e.getCause());  // 得到异常的具体信息
    121         }
    122         
    123     }
    124     
    125     /**
    126      * 反射进行域处理的例子
    127      */
    128     private void testFields() {
    129         // 同样测试getField和getDeclareField的区别
    130         Field[] fields = Child.class.getFields();
    131         System.out.println();
    132         /**
    133          * 输出为:
    134              field3
    135             field3
    136            可以看出这时候获得了父和子中所有的public的field
    137          */
    138         for (Field field : fields) {
    139             System.out.println(field.getName());
    140         }
    141         
    142         fields = Child.class.getDeclaredFields();
    143         System.out.println();
    144         /**
    145          * 输出为:
    146             field0
    147             field1
    148             field2
    149             field3
    150             可以看出此时输出了自己本身这个类中的所有域而不仅仅是public的
    151          */
    152         for (Field field : fields) {
    153             System.out.println(field.getName());
    154             // 给私有的域设置值需要先调用 setAccessible(true),否则会报权限错误。
    155         }
    156     }
    157     
    158     private void testMethods() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    159         Method[] methods = Child.class.getMethods();
    160         System.out.println();
    161         /**
    162          * 输出为:
    163               parentMethod
    164             wait
    165             wait
    166             wait
    167             equals
    168             toString
    169             hashCode
    170             getClass
    171             notify
    172             notifyAll
    173             可以看出把所有继承层次中(包括Object)的public方法都或得到了
    174          */
    175         for (Method method : methods) {
    176             System.out.println(method.getName());
    177         }
    178         
    179         methods = Child.class.getDeclaredMethods();
    180         System.out.println();
    181         /**
    182          * 输出为:
    183              ChildMethod
    184              只是获得了当前类中的所有方法
    185          */
    186         for (Method method : methods) {
    187             System.out.println(method.getName());
    188             // 对于私有的method如果直接调用会抛出异常但是通过 method.setAccessible(true)就可以解决这一问题。
    189         }
    190     }
    191     
    192     /**
    193      * 用反射实现的设置某个属性值的方法
    194      * 通过反射API,java也可以应用在灵活性很高的场景中,最长见的Servlet中http请求参数值的填充。
    195      * 虽然随着java虚拟机性能的改进,反射API的性能有所提升。但是反射方法和非反射方法的性能差距还是客观存在的。
    196      * 因此在一些性能要求很高的场景中要慎用反射API或者将常调用的反射获得的方法先缓存起来。
    197      */
    198     void invokeSetter(Object obj, String field, Object value) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    199         String methodName = "set" + field.substring(0, 1).toUpperCase() + field.substring(1);
    200         Class<?> clazz = obj.getClass();
    201         Method setMethod = clazz.getMethod(    methodName, value.getClass());
    202         setMethod.invoke(obj, value);
    203     }
    204 }
    205 
    206 class Parent {
    207     String field0;
    208     private String field1;
    209     protected String field2;
    210     public String field3;
    211     
    212     public Parent(double a) {}
    213     public Parent() {}
    214     public void parentMethod() {}
    215 }
    216 
    217 class Child extends Parent  {
    218     String field0;
    219     private String field1;
    220     protected String field2;
    221     public String field3;
    222     
    223     // 如果父类没有同样的构造函数,则默认会调用父类的无参构造函数,如果父类没有无参构造函数,则编译会报错,会要求显示调用父类的某一个构造函数,以确保父类会在子类被实例化之前被实例化。
    224     public Child(int i) {}
    225     private Child(long l) {}
    226     private void ChildMethod() {}
    227 }
    228 
    229 class VaragsConstructor {
    230     public VaragsConstructor(int... varags) {};
    231 }
    232 
    233 class NonStaticNestedClass {
    234     class NestedClass {
    235         NestedClass(int i) {}
    236     }
    237 }
    ReflectionAPI
  • 相关阅读:
    认识hasLayout——IE浏览器css bug的一大罪恶根源 转
    web网站p教程 转
    可遇不可求的Question之SQLServer的INSERT ON DUPLICATE KEY UPDATE语法篇
    可遇不可求的Question之Protoc.exe无法编译proto文件篇
    python各个版本的下载地址
    可遇不可求的Question之WCF发布无法运行篇
    [转]理解JSON:3分钟课程
    可遇不可求的Question之Silverlight发布IIS设置篇
    可遇不可求的Question之C#中的匿名事件导致内存泄露的解决篇
    可遇不可求的Question之mysql连接数暴增的解决方法篇
  • 原文地址:https://www.cnblogs.com/Kidezyq/p/5773673.html
Copyright © 2020-2023  润新知