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
原文地址:https://www.cnblogs.com/flyme/p/4577113.html