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

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

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

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

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

下面是我的练习程序:

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

 package com.dxjia.sample;

 public class UserBean {
private String mName;
private int mAge;
private String mVersion = "1.0"; public UserBean() {
System.out.println(" UserBean Constructor1 called!");
} public UserBean(String name, int age) {
System.out.println(" UserBean Constructor2 called!");
init(name, age);
} public void setName(String name) {
mName = name;
System.out.println(" UserBean setName() done");
} public String getName() {
return mName;
} public void setAge(int age) {
mAge = age;
System.out.println(" UserBean setAge() done");
} public int getAge() {
return mAge;
} private void init(String name, int age) {
mName = name;
mAge = age;
} public void printVersion() {
System.out.println(" UserBean VERSION: " + mVersion);
} public void printName() {
System.out.println(" UserBean mName [" + mName + "]");
} public void printAge() {
System.out.println(" UserBean mAge [" + mAge + "]");
} private void printUserInfo() {
System.out.println(" UserBean mName [" + mName + "] " + "mAge [" + mAge + "]");
}
}

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

 import java.lang.*;
import java.lang.reflect.*; public class Test { public static void main(String[] args) { try {
Class c = Class.forName("com.dxjia.sample.UserBean");
if (null == c) {
System.out.println("can`t load class!");
return;
} System.out.println("\n--------------获取类的所有信息----------------------\n"); // 获取类的修饰符,public private...
int mod = c.getModifiers();
String modifier = Modifier.toString(mod);
System.out.println("modifier : " + modifier); // 获取父类
Class superClass = c.getSuperclass();
String superClassName = superClass.getName();
System.out.println("superClassName : " + superClassName); // 获取implements的接口
Class[] interfaces = c.getInterfaces();
if (interfaces.length != 0) {
for (Class cl : interfaces) {
System.out.println("interfacesName : " + cl.getName());
}
} else {
System.out.println("interfacesName : ");
} // 获取所有的成员变量
Field[] fields = c.getDeclaredFields();
if (fields.length != 0) {
System.out.println("fields : ");
for (Field field : fields) {
modifier = Modifier.toString(field.getModifiers());
Class type = field.getType();
String name = field.getName();
if (type.isArray()) {
String arrType = type.getComponentType().getName() + "[]";
System.out.println(" " + modifier + " " + arrType + " " + name + ";");
} else {
System.out.println(" " + modifier + " " + type + " " + name + ";");
}
}
} else {
System.out.println("fields : ");
} // 获取所有的构造函数
Constructor[] constructors = c.getDeclaredConstructors();
if(constructors.length != 0) {
System.out.println("constructors : ");
for (Constructor constructor : constructors) {
// 构造方法名
String name = constructor.getName();
// 获取访问修饰符,public private protected
modifier = Modifier.toString(constructor.getModifiers());
System.out.print(" " + modifier +" " + name + "(");
// 获取构造方法中的所有参数, paramTypes.length为0,说明是无参构造函数
Class[] paramTypes = constructor.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) {
System.out.print(", ");
}
if (paramTypes[i].isArray()) {
System.out.print(paramTypes[i].getComponentType().getName()+"[]");
} else {
System.out.print(paramTypes[i].getName());
}
}
System.out.print(")\n");
}
} else {
System.out.println("constructors : ");
} // 获取所有的成员函数
Method[] methods = c.getDeclaredMethods();
if(methods.length != 0) {
System.out.println("methods : ");
for (Method method: methods) {
// 获取方法的描述符,private public protected...
modifier = Modifier.toString(method.getModifiers());
// 获取方法的返回类型
Class returnType = method.getReturnType();
if (returnType.isArray()) {
String arrType = returnType.getComponentType().getName()+"[]";
System.out.print(" " + modifier + " " + arrType + " " + method.getName() + "(");
} else {
System.out.print(" " + modifier + " " + returnType.getName() + " " + method.getName() + "(");
}
// 获取所有的参数信息
Class[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) {
System.out.print(",");
}
if (paramTypes[i].isArray()) {
System.out.println(paramTypes[i].getComponentType().getName()+"[]");
} else {
System.out.print(paramTypes[i].getName());
}
}
System.out.println(");");
}
} else {
System.out.println("methods : ");
} System.out.println("\n----------------测试使用----------------------\n"); /**
* 测试反射,调用函数,变量赋值等
* 反射的使用一般都会先像上面这样打印出来,进行一个分析之后,
* 再编写类似下面的代码来反射调用类的函数,也就是自己先通过上面的方式来了解这个类,
* 然后再hard code反射使用这个类中对自己有用的函数来达到目的。当然,我们比较了解那个类了,只是环境中没有公开,所以我们需要反射
*/
// 首先可以实例化对象,因为万物都继承自Object
// 所以这里用Object来声明定义对象,不影响使用
// 直接使用Class.newInstance()函数,是调用的类的无参构造函数
System.out.println("调用无参构造函数");
Object bean1 = c.newInstance(); // 如果要调用有参构造函数,那就要使用下面的方式
Class[] paramTypes = {String.class, int.class};
Constructor con = c.getConstructor(String.class, int.class);
// 使用
System.out.println("调用有参构造函数");
Object bean2 = con.newInstance("小明", 16); // 调用bean2 public 函数 printVersion()
System.out.println("执行public printVersion()");
Method method1 = c.getDeclaredMethod("printVersion");
method1.invoke(bean2); // 调用bean2 private函数 printUserInfo()
System.out.println("执行public printUserInfo()");
Method method2 = c.getDeclaredMethod("printUserInfo");
// 因为printUserInfo是private方法,所以需要加上这句来避免安全检查,这样才可以调用私有方法
method2.setAccessible(true);
// 执行
method2.invoke(bean2); // 调用有参数的函数 setName() setAge()
System.out.println("调用有参数函数设置新name和age");
Method method3 = c.getDeclaredMethod("setName", String.class);
method3.invoke(bean2, "张三");
Method method4 = c.getDeclaredMethod("setAge", int.class);
method4.invoke(bean2, 25); // 调用 printUserInfo 将新值打印出来
System.out.println("打印新值");
method2.invoke(bean2); // 直接操作成员变量,给私有成员变量赋值,记得加setAccessible(true);
Field field = c.getDeclaredField("mVersion");
field.setAccessible(true);
String oldVersion = (String) field.get(bean2);
System.out.println("直接获取私有变量mVersion的值,并打印:" + oldVersion);
System.out.println("直接将私有成员变量mVersion赋值2.0");
field.set(bean2, "2.0");
// 调用printVersion()打印新值
System.out.println("打印新值");
method1.invoke(bean2);
} catch (ClassNotFoundException e) {
System.out.println("exception: " + e.toString());
} catch (InstantiationException e) {
System.out.println("exception: " + e.toString());
} catch (IllegalAccessException e) {
System.out.println("exception: " + e.toString());
} catch (NoSuchMethodException e) {
System.out.println("exception: " + e.toString());
} catch (InvocationTargetException e) {
System.out.println("exception: " + e.toString());
} catch (NoSuchFieldException e) {
System.out.println("exception: " + e.toString());
}
} }

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

 javac com\dxjia\sample\UserBean.java
javac -encoding UTF-8 -Xlint:unchecked Test.java

编译通过后,执行:

 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

最新文章

  1. Rdlc报表出现空白页解决方法
  2. 上门洗车App 竟然是块大肥肉!
  3. (step4.3.5)hdu 1501(Zipper——DFS)
  4. linux源码分析2
  5. 转 scrollLeft,scrollWidth,clientWidth,offsetWidth之完全详解
  6. Java GC机制和对象Finalize方法的一点总结
  7. Android----获取activity上所有的控件
  8. Linux新手笔记 sudo
  9. Delphi 悬浮窗口、浮动窗口的实现
  10. Useful command for Docker
  11. Unity-修改Debug日志文本颜色
  12. idea使用的小技巧总结
  13. JS整理--闭包
  14. nc 画界面,触发效果(第一种)
  15. 【读书笔记】iOS-软件测试与iOS测试
  16. 二叉搜索树的后序遍历序列(python)
  17. scala中Stream理解
  18. Oracle EBS PO退货失败
  19. Java 子类父类构造方法执行顺序
  20. IOException while loading persisted sessions:

热门文章

  1. mysql主主复制(双主复制)配置步骤
  2. 斯坦福第七课:正则化(Regularization)
  3. ie6下内容会撑开父级设置好的宽高
  4. HDU-3548-Enumerate the Triangles
  5. 平衡树模板 bzoj 3224
  6. 【基础知识】.Net基础加强10天
  7. Dynamic CRM 2013学习笔记(二十七)无代码 复制/克隆方法
  8. Dynamic CRM 2013学习笔记(三十一)自定义用excel批量导入实体数据
  9. ASP.NET Core 源码阅读笔记(3) ---Microsoft.AspNetCore.Hosting
  10. C#设计模式(8)——桥接模式(Bridge Pattern)