• Java 反射练习


    已同步更新至个人blog:http://dxjia.cn/2015/08/java-reflect/    

      引用baidubaike上对JAVA反射的说明,如下:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(成员变量和函数);对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

        而能够使JAVA有这样的能力,归根结底是由于JVM,而小一点说,是因为有Class对象的存在,我在上一篇文章中有讲解JAVA的Class对象,它是在类加载完后,每个类都会产生的一个实例,而其内部详细描述了这个类的情况,所以我们可以通过这个Class对象来得到任何有关这个类的细节,不仅仅能了解这个类,java还提供了方法来动态执行这个类里的方法或修改成员变量的值。

    反射机制的优点与缺点:(参考:【Java反射机制】)

    为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
      静态编译:在编译时确定类型,绑定对象,即通过。
      动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
      一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编
    译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能
    的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功 能。
      它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

    下面是我的练习程序:

    在目录下新建comdxjiasample路径,然后在sample下新建一个UserBean.java的文件,这将是我们用来进行反射的类。代码如下:

     1 package com.dxjia.sample;
     2 
     3 public class UserBean {
     4     private String mName;
     5     private int mAge;
     6     private String mVersion = "1.0";
     7 
     8     public UserBean() {
     9         System.out.println("    UserBean Constructor1 called!");
    10     }
    11 
    12     public UserBean(String name, int age) {
    13         System.out.println("    UserBean Constructor2 called!");
    14         init(name, age);
    15     }
    16     
    17     public void setName(String name) {
    18         mName = name;
    19         System.out.println("    UserBean setName() done");
    20     }
    21     
    22     public String getName() {
    23         return mName;
    24     }
    25 
    26     public void setAge(int age) {
    27         mAge = age;
    28         System.out.println("    UserBean setAge() done");
    29     }
    30     
    31     public int getAge() {
    32         return mAge;
    33     }
    34     
    35     private void init(String name, int age) {
    36         mName = name;
    37         mAge = age;
    38     }
    39     
    40     public void printVersion() {
    41         System.out.println("    UserBean VERSION: " + mVersion);
    42     }
    43     
    44     public void printName() {
    45         System.out.println("    UserBean mName [" + mName + "]");
    46     }
    47     
    48     public void printAge() {
    49         System.out.println("    UserBean mAge [" + mAge + "]");
    50     }
    51 
    52     private void printUserInfo() {
    53         System.out.println("    UserBean mName [" + mName + "] " + "mAge [" + mAge + "]");
    54     }
    55 }

    然后在根目录下新建Test.java文件,这里实现我们的测试程序,代码如下【注意注释】:

      1 import java.lang.*;
      2 import java.lang.reflect.*;
      3 
      4 public class Test {
      5 
      6     public  static void main(String[] args) {
      7 
      8         try {
      9             Class c = Class.forName("com.dxjia.sample.UserBean");
     10             if (null == c) {
     11                 System.out.println("can`t load class!");
     12                 return;
     13             }
     14 
     15             System.out.println("
    --------------获取类的所有信息----------------------
    ");
     16 
     17             // 获取类的修饰符,public private...
     18             int mod = c.getModifiers();
     19             String modifier = Modifier.toString(mod);
     20             System.out.println("modifier       : " + modifier);
     21 
     22             // 获取父类
     23             Class superClass = c.getSuperclass();
     24             String superClassName = superClass.getName();
     25             System.out.println("superClassName : " + superClassName);
     26             
     27             // 获取implements的接口
     28             Class[] interfaces = c.getInterfaces();
     29             if (interfaces.length != 0) {
     30                 for (Class cl : interfaces) {
     31                 System.out.println("interfacesName : " + cl.getName());
     32                 }
     33             } else {
     34                 System.out.println("interfacesName : ");
     35             }
     36             
     37             // 获取所有的成员变量
     38             Field[] fields = c.getDeclaredFields();
     39             if (fields.length != 0) {
     40                 System.out.println("fields         : ");
     41                 for (Field field : fields) {
     42                     modifier = Modifier.toString(field.getModifiers());
     43                     Class type = field.getType();
     44                     String name = field.getName();
     45                     if (type.isArray()) {
     46                         String arrType = type.getComponentType().getName() + "[]";
     47                         System.out.println("                 " + modifier + " " + arrType + " " + name + ";");
     48                     } else {
     49                         System.out.println("                 " + modifier + " " + type + " " + name + ";");
     50                     }
     51                 }
     52             } else {
     53                 System.out.println("fields         : ");
     54             }
     55             
     56             // 获取所有的构造函数
     57             Constructor[] constructors = c.getDeclaredConstructors();
     58             if(constructors.length != 0) {
     59                 System.out.println("constructors   : ");
     60                 for (Constructor constructor : constructors) {
     61                     // 构造方法名
     62                     String name = constructor.getName();
     63                     // 获取访问修饰符,public private protected
     64                     modifier = Modifier.toString(constructor.getModifiers());
     65                     System.out.print("                 " + modifier +" " + name + "(");
     66                     // 获取构造方法中的所有参数, paramTypes.length为0,说明是无参构造函数
     67                     Class[] paramTypes = constructor.getParameterTypes();
     68                     for (int i = 0; i < paramTypes.length; i++) {
     69                         if (i > 0) {
     70                             System.out.print(", ");
     71                         }
     72                         if (paramTypes[i].isArray()) {
     73                             System.out.print(paramTypes[i].getComponentType().getName()+"[]");
     74                         } else {
     75                             System.out.print(paramTypes[i].getName());
     76                         }
     77                     }
     78                     System.out.print(")
    ");
     79                 }
     80             } else {
     81                 System.out.println("constructors   : ");
     82             }
     83             
     84             //  获取所有的成员函数
     85             Method[] methods = c.getDeclaredMethods();
     86             if(methods.length != 0) {
     87                 System.out.println("methods        : ");
     88                 for (Method method: methods) {
     89                     // 获取方法的描述符,private public protected...
     90                     modifier = Modifier.toString(method.getModifiers());
     91                     // 获取方法的返回类型
     92                     Class returnType = method.getReturnType();
     93                     if (returnType.isArray()) {
     94                         String arrType = returnType.getComponentType().getName()+"[]";
     95                         System.out.print("                  " + modifier + " " + arrType + " " + method.getName() + "(");
     96                     } else {
     97                         System.out.print("                 " + modifier + " " + returnType.getName() + " " + method.getName() + "(");
     98                     }
     99                     // 获取所有的参数信息
    100                     Class[] paramTypes = method.getParameterTypes();
    101                     for (int i = 0; i < paramTypes.length; i++) {
    102                         if (i > 0) {
    103                             System.out.print(",");
    104                         }
    105                         if (paramTypes[i].isArray()) {
    106                             System.out.println(paramTypes[i].getComponentType().getName()+"[]");
    107                         } else {
    108                             System.out.print(paramTypes[i].getName());
    109                         }
    110                     }
    111                     System.out.println(");");
    112                 }    
    113             } else {
    114                 System.out.println("methods        : ");
    115             }
    116 
    117             System.out.println("
    ----------------测试使用----------------------
    ");
    118 
    119             /**
    120              * 测试反射,调用函数,变量赋值等
    121              * 反射的使用一般都会先像上面这样打印出来,进行一个分析之后,
    122              * 再编写类似下面的代码来反射调用类的函数,也就是自己先通过上面的方式来了解这个类,
    123              * 然后再hard code反射使用这个类中对自己有用的函数来达到目的。当然,我们比较了解那个类了,只是环境中没有公开,所以我们需要反射
    124              */
    125             // 首先可以实例化对象,因为万物都继承自Object
    126             // 所以这里用Object来声明定义对象,不影响使用
    127             // 直接使用Class.newInstance()函数,是调用的类的无参构造函数
    128             System.out.println("调用无参构造函数");
    129             Object bean1 = c.newInstance();
    130             
    131             // 如果要调用有参构造函数,那就要使用下面的方式
    132             Class[] paramTypes = {String.class, int.class};
    133             Constructor con = c.getConstructor(String.class, int.class);
    134             // 使用
    135             System.out.println("调用有参构造函数");
    136             Object bean2 = con.newInstance("小明", 16);    
    137             
    138             // 调用bean2 public 函数 printVersion()
    139             System.out.println("执行public printVersion()");
    140             Method method1 = c.getDeclaredMethod("printVersion");
    141             method1.invoke(bean2);
    142 
    143             // 调用bean2 private函数 printUserInfo()
    144             System.out.println("执行public printUserInfo()");
    145             Method method2 = c.getDeclaredMethod("printUserInfo");
    146             // 因为printUserInfo是private方法,所以需要加上这句来避免安全检查,这样才可以调用私有方法
    147             method2.setAccessible(true);
    148             // 执行
    149             method2.invoke(bean2);
    150             
    151             // 调用有参数的函数 setName()  setAge()
    152             System.out.println("调用有参数函数设置新name和age");
    153             Method method3 = c.getDeclaredMethod("setName", String.class);
    154             method3.invoke(bean2, "张三");
    155             Method method4 = c.getDeclaredMethod("setAge", int.class);
    156             method4.invoke(bean2, 25);
    157             
    158             // 调用 printUserInfo 将新值打印出来
    159             System.out.println("打印新值");
    160             method2.invoke(bean2);
    161             
    162             // 直接操作成员变量,给私有成员变量赋值,记得加setAccessible(true);
    163             Field field = c.getDeclaredField("mVersion");
    164             field.setAccessible(true);
    165             String oldVersion = (String) field.get(bean2);
    166             System.out.println("直接获取私有变量mVersion的值,并打印:" + oldVersion);
    167             System.out.println("直接将私有成员变量mVersion赋值2.0");
    168             field.set(bean2, "2.0");
    169             // 调用printVersion()打印新值
    170             System.out.println("打印新值");
    171             method1.invoke(bean2);
    172         } catch (ClassNotFoundException e) {
    173             System.out.println("exception: " + e.toString());
    174         } catch (InstantiationException e) {
    175             System.out.println("exception: " + e.toString());
    176         } catch (IllegalAccessException e) {
    177             System.out.println("exception: " + e.toString());
    178         } catch (NoSuchMethodException e)  {
    179             System.out.println("exception: " + e.toString());
    180         } catch (InvocationTargetException e) {
    181             System.out.println("exception: " + e.toString());
    182         } catch (NoSuchFieldException e) {
    183             System.out.println("exception: " + e.toString());
    184         }
    185     }
    186 
    187 }

    打开cmd,切换到该目录下,执行

    1 javac comdxjiasampleUserBean.java
    2 javac -encoding UTF-8 -Xlint:unchecked Test.java

    编译通过后,执行:

    1 java Test

    打印如下:

    --------------获取类的所有信息----------------------
    
    modifier       : public
    superClassName : java.lang.Object
    interfacesName :
    fields         :
                     private class java.lang.String mName;
                     private int mAge;
                     private class java.lang.String mVersion;
    constructors   :
                     public com.dxjia.sample.UserBean()
                     public com.dxjia.sample.UserBean(java.lang.String, int)
    methods        :
                     public int getAge();
                     public void printName();
                     public void printAge();
                     public java.lang.String getName();
                     private void init(java.lang.String,int);
                     public void setName(java.lang.String);
                     public void setAge(int);
                     public void printVersion();
                     private void printUserInfo();
    
    ----------------测试使用----------------------
    
    调用无参构造函数
        UserBean Constructor1 called!
    调用有参构造函数
        UserBean Constructor2 called!
    执行public printVersion()
        UserBean VERSION: 1.0
    执行public printUserInfo()
        UserBean mName [小明] mAge [16]
    调用有参数函数设置新name和age
        UserBean setName() done
        UserBean setAge() done
    打印新值
        UserBean mName [张三] mAge [25]
    直接获取私有变量mVersion的值,并打印:1.0
    直接将私有成员变量mVersion赋值2.0
    打印新值
        UserBean VERSION: 2.0
  • 相关阅读:
    JAVA并发-CountDownLatch
    【转载】Makedown数学公式语法
    算法的时间复杂度
    JVM-卡表(Card Table)
    sync.WaitGroup的使用以及坑
    go 多协程爬取图片
    go ioutial 读取写入文件
    go 下载图片
    go 正则 爬取邮箱代码
    go 解析path
  • 原文地址:https://www.cnblogs.com/flyme/p/4577113.html
Copyright © 2020-2023  润新知