Java 反射
来源:互联网 发布:遗传算法原理与应用 编辑:程序博客网 时间:2024/06/01 10:34
一、Java 语言的反射机制
在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?
答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
Java 反射机制主要提供了以下功能:
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法
Reflection 允许程序在运行时透过Reflection APIs取得任何一个 已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods。
那么反射这么厉害,java是不是动态语言呢?
来看一下动态语言百科上的定义:
动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。
从这个角度看很明显,发现java不是动态语言
尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或调用其methods。
二、Java Reflection API 简介
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
- Class类:代表一个类。
- Field 类:代表类的成员变量(成员变量也称为类的属性)。
- Method类:代表类的方法。
- Constructor 类:代表类的构造方法。
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法
具体如下:
常用方法用法:
1、获得对象的类型
Class classType=object.getClass();
在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它有以下方法:
- getName():获得类的完整名字。
- getFields():获得类的public类型的属性。
- getDeclaredFields():获得类的所有属性。
- getMethods():获得类的public类型的方法。
- getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):
获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
2、通过默认构造方法创建一个新对象
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
3、获得对象的所有属性
Field fields[]=classType.getDeclaredFields();
Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。
获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性拷贝到新的对象中
4、动态创建和访问数组
java.lang.Array 类提供了动态创建和访问数组元素的各种静态方法。
三、Class
众所周知Java有个Object class,是所有Java classes的继承根源,其内声明了数个应该在所有Java class中被改写的methods:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class object。
Class class十分特殊。它和一般classes一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types
(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class object。
如果您想借由“修改Java标准库源码”来观察Class object的实际生成时机(例如在Class的constructor内添加一个println()),不能够!因为Class并没有public constructor。
Class是Reflection起源。针对任何您想探勘的class,唯有先为它产生一个Class object,接下来才能经由后者唤起众多的Reflection APIs。
1、“Class” object的取得途径。
Java允许我们从多种途径为一个class生成对应的Class object
四、应用
代码操作的实体类:
1、构造函数无参
/** * Created by jiankunking on 2016/9/16. */public class entityClassWithoutParameter{ public int getAddResult(int a, int b) { return a + b; } private int getMultiplyResult(int a, int b) { return a * b; } public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } public String field1; protected String field2; private String field3 = "我是私有的"; /** * 测试私有函数是否可见 * @return */ private String testPrivate(String string) { System.out.println("testPrivate:"+string); return string; }}
2、构造函数有参
/** * Created by jiankunking on 2016/9/16. */public class entityClassWithParameter{ public entityClassWithParameter(String string, int num) { System.out.println("我是entityClassWithParameter:" + string + num); }}
1、运行时生成instances
在Reflection 动态机制中有两种作法:一个针对“无参ctor”,一个针对“带参数ctor”。如果欲调用的是“带参数ctor“就比较麻烦些,不再调用Class的newInstance(),而是调用Constructor 的newInstance()。
无参:
//获取 指定类Class classType = Class.forName("entityClassWithoutParameter");//创建 无参 对象Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
有参:
//创建 有参 对象Class cls = Class.forName("entityClassWithParameter");Class[] paramTypes = {String.class, int.class};// 方法传入的参数Object[] params = {"我是string参数", 23};Constructor con = cls.getConstructor(paramTypes);//主要就是这句了entityClassWithParameter base = (entityClassWithParameter) con.newInstance(params);
2、运行时调用methods
首先准备一个Class[]做为参数类型(本例指定其中一个是String,另一个是int),然后以此为自变量调用getMethod(),获得特定的Method object。接下来准备一个Object[]放置参数变量,然后调用上述所得之特定Method object的invoke()。
//获取 指定类Class classType = Class.forName("entityClassWithoutParameter");//获取 指定方法Method addMethod = classType.getMethod("getAddResult", new Class[]{int.class, int.class});//调用函数 并接收结果Object result = addMethod.invoke(classType.newInstance(), new Object[]{new Integer(100), new Integer(200)});
为什么获得Method object时不需指定回返类型?
因为method overloading机制要求signature必须唯一,而回返类型并非signature的一个成份。换句话说,只要指定了method名称和参数列,就一定指出了一个独一无二的method。
3、运行时变更fields内容
首先调用Class的getField()并指定field名称。
获得特定的Field object之后便可直接调用Field的get()和set(),
//获取private字段 Field f = classType.getDeclaredField("field3"); //修改protected、private字段的可见性 public字段不需要这句 f.setAccessible(true); //创建 无参 对象 Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); System.out.println("获取私有字段值:" + f.get(objectCopy)); f.set(objectCopy,"我要修改自己"); System.out.println("获取私有字段值:" + f.get(objectCopy));
效果如下:
4、对类的私有变量和私有方法的访问
//获取private字段 Field f = classType.getDeclaredField("field3"); //修改protected、private字段的可见性 public字段不需要这句 f.setAccessible(true); //创建 无参 对象 Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); System.out.println("获取私有字段值:" + f.get(objectCopy)); f.set(objectCopy, "我要修改自己"); System.out.println("获取私有字段值:" + f.get(objectCopy)); //获得私有方法 Method method = classType.getDeclaredMethod("testPrivate", new Class[]{String.class}); //设置私有方法可以被访问 method.setAccessible(true); //调用私有方法 String str = (String) method.invoke(objectCopy, new Object[]{"测试私有方法是否可以通过反射调用"}); System.out.println("我是私有方法返回值:"+str);//输出 测试私有方法是否可以通过反射调用
完整测试代码
import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * Created by jiankunking on 2016/7/31. */public class test{ public static void main(final String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException { //获取 指定类 Class classType = Class.forName("entityClassWithoutParameter"); //获取 指定方法 Method addMethod = classType.getMethod("getAddResult", new Class[]{int.class, int.class}); //调用函数 并接收结果 Object result = addMethod.invoke(classType.newInstance(), new Object[]{new Integer(100), new Integer(200)}); //输出 结果 System.out.println("加法结果:" + (Integer) result); //获取 所有方法 for (Method item : classType.getDeclaredMethods()) { System.out.println("函数名:" + item.getName()); } //获取 所有public字段 for (Field item : classType.getFields()) { System.out.println("字段名:" + item.getName()); } //获取private字段 Field f = classType.getDeclaredField("field3"); //修改protected、private字段的可见性 public字段不需要这句 f.setAccessible(true); //创建 无参 对象 Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); System.out.println("获取私有字段值:" + f.get(objectCopy)); f.set(objectCopy, "我要修改自己"); System.out.println("获取私有字段值:" + f.get(objectCopy)); //获得私有方法 Method method = classType.getDeclaredMethod("testPrivate", new Class[]{String.class}); //设置私有方法可以被访问 method.setAccessible(true); //调用私有方法 String str = (String) method.invoke(objectCopy, new Object[]{"测试私有方法是否可以通过反射调用"}); System.out.println("我是私有方法返回值:"+str);//输出 测试私有方法是否可以通过反射调用 //创建 有参 对象 Class cls = Class.forName("entityClassWithParameter"); Class[] paramTypes = {String.class, int.class}; // 方法传入的参数 Object[] params = {"我是string参数", 23}; Constructor con = cls.getConstructor(paramTypes); //主要就是这句了 entityClassWithParameter base = (entityClassWithParameter) con.newInstance(params); }}
结果如下:
本文部分参考百度百科及网络资料:JAVA反射机制
演示demo下载:
http://download.csdn.net/detail/xunzaosiyecao/9631373
作者:jiankunking 出处:http://blog.csdn.net/jiankunking
- 【反射】JAVA反射机制
- JAVA 反射
- java 反射
- Java反射
- java反射
- java反射
- JAVA反射
- java 反射
- Java 反射
- java 反射
- Java反射
- java反射
- JAVA 反射
- java 反射
- Java反射
- java反射
- java 反射
- java 反射
- POJ2251-简单三维BFS
- android学习--------Gestures(手势)
- Java中public,protected,private以及默认的访问权限作用域
- lk中的bio机制 2
- cuda初步认识
- Java 反射
- RandomAccessFile 基础
- Xcode模拟器不显示iOS版本
- 【演歌】加賀の女 歌词翻译
- 19. Remove Nth Node From End of List
- bzoj2152(树形dp或点分治)
- Python下Pip安装包下的AttributeError: 'Requirement' object has no attribute 'project_name'
- C++安全函数之strcat_s
- 【容斥原理】