1、定义
Java的反射技术是java程序的特征之一,它允许运行中的Java程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。
使用反射可以获得Java类中各个成员的名称并显示出来。简单的说,反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。
一句话:运行时探究和使用编译时未知的类。
2、反射原理
对象创建过程:比如要创建Dog类的三个对象
Dog d1 = new Dog();
Dog d2 = new Dog();
Dog d3 = new Dog();
在这个过程中,JVM的底层实现过程如下:
1.JVM利用DogClassLoader先将Dog类加载到内存,然后马上产生了一个Class类型的对象,该对象可以看成是一个模型,以后无论创建多少个Dog类的实例都是利用该模型来生成。
所以一个类所对应的Class类型的对象只有一个。
2.根据这个模型生成Dog类的三个实例d1、d2、d3。反射正是利用了java的这种加载方式主动完成了对象的创建及使用。
3、使用步骤
遵循三个步骤
第一步是获得你想操作的类的 java.lang.Class 对象
第二步是调用诸如 getDeclaredMethods 的方法
第三步使用 reflection API 来操作这些信息
第一步:获取Class对象
获得Class对象的方式主要有以下三种:
方式一:如果一个类的实例已经得到,你可以使用
【Class c = 对象名.getClass(); 】
//例如
TextField t = new TextField();
Class c = t.getClass();
Class s = c.getSuperclass();
方式二:如果你在编译期知道类的名字,你可以使用如下的方法
Class c = JButton.class; 或者 Class c = Integer.TYPE;
方式三:如果类名在编译期不知道, 但是在运行期可以获得, 你可以使用下面的方法
Class c = Class.forName(strg);
第二步:探究类的信息
一个类通常由三部分组成——属性、普通方法、构造方法。
反射机制中为获取以上三个部分分别提供了常用类及方法。
Filed类:提供有关类或接口的属性信息。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。
Method类:提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
Filed类
Filed类常用方法:
Field getField(String name) 获得指定的公共字段
Field[] getFields() 获得类的所有公共字段
Field getDeclaredField(String name) 获得指定的字段
Field[] getDeclaredFields() 获得类声明的所有字段
使用示例代码:
System.out.println("---------------------类-------------------------------");
// 获取类
Class userClass = Class.forName("com.xxx.classroom.User");
System.out.println(userClass);
System.out.println("---------------------属性-------------------------------");
// 获取类中的全部属性数组
Field[] field = userClass.getDeclaredFields();
for (Field field2 : field) {
// 属性的注解 Modifier
int i = field2.getModifiers();
// 数据类型
AnnotatedType annotatedType = field2.getAnnotatedType();
// 获取属性名字
String className = field2.getName();
System.out.print(i + " " + annotatedType.getType() + " " + className);
System.out.println();
System.out.println(field2);
}
System.out.println("-----------------隔离线-----------------------");
// 通过属性名字获取属性所有都可以获取
Field fid = userClass.getDeclaredField("id");
System.out.println(fid);
System.out.println("-----------------隔离线-----------------------");
// 获取类中的公共属性数组
Field[] fields = userClass.getFields();
for (Field field2 : fields) {
System.out.println(field2);
}
System.out.println("-----------------隔离线-----------------------");
// 通过属性名字获取属性可以获取公共属性
Field fidPublic = userClass.getField("userName");
System.out.println(fidPublic);
Constructor类
Constructor类常用方法:
//获得使用特殊的参数类型的公共构造函数
Constructor getConstructor(Class[] params)
// 获得类的所有公共构造函数
Constructor[] getConstructors()
//获得使用特定参数类型的构造函数(与访问级别无关)
Constructor getDeclaredConstructor(Class[] params)
//获得类的所有构造函数(与访问级别无关)
Constructor[] getDeclaredConstructors()
代码示例:
System.out.println("---------------------类-------------------------------");
// 获取类
Class userClass = Class.forName("com.xxx.classroom.User");
System.out.println(userClass);
// 获取类中所有构造方法
Constructor[] constructorAll = userClass.getDeclaredConstructors();
for (Constructor constructor : constructorAll) {
System.out.println(constructor);
}
System.out.println("-----------------隔离线-----------------------");
// 获取类中所有公共构造方法
Constructor[] constructorArray = userClass.getConstructors();
for (Constructor constructor : constructorArray) {
System.out.println(constructor);
// 参数个数
System.out.println(constructor.getParameterCount());
// 参数类型
Class[] claArray = constructor.getParameterTypes();
for (Class c : claArray) {
System.out.println(c.getName());
}
}
Method类
Method类常用方法:
//使用特定的参数类型,获得命名的公共方法
Method getMethod(String name, Class[] params)
//获得类的所有公共方法
Method[] getMethods()
//使用特定的参数类型,获得类声明的命名的方法
Method getDeclaredMethod(String name, Class[] params)
//获得类声明的所有方法
Method[] getDeclaredMethods()
代码示例:
System.out.println("---------------------类-------------------------------");
// 获取类
Class userClass = Class.forName("com.xxx.classroom.User");
System.out.println(userClass);
System.out.println("---------------------方法-------------------------------");
// 获取类中的全部方法
Method[] methods = userClass.getDeclaredMethods();
for (Method method2 : methods) {
// 属性的注解 Modifier
int i = method2.getModifiers();
// 返回数据类型
AnnotatedType annotatedType = method2.getAnnotatedReturnType();
// 获取方法名字
String className = method2.getName();
// 获取注解
Annotation[] a = method2.getDeclaredAnnotations();
System.out.println("注解个数:" + a.length);
for (Annotation a2 : a) {
System.out.println(a2.annotationType());
}
// 参数个数
System.out.println("参数个数:" + method2.getParameterCount());
// 获取形式参数列表的数据类型
Type[] type = method2.getParameterTypes();
System.out.println("参数个数type:" + type.length);
System.out.print(i + " " + annotatedType.getType() + " " + className + " ");
for (Type t : type) {
System.out.print(t.getTypeName() + " ");
}
System.out.println();
System.out.println(method2);
}
System.out.println("-----------------隔离线-----------------------");
// 获取已知任意方法
Method methodAll = userClass.getDeclaredMethod("insert", java.lang.Long.class);
System.out.println(methodAll);
System.out.println("-----------------隔离线-----------------------");
// 获取类中的所有的公共方法包括从父类继承下来的
Method[] methods1 = userClass.getMethods();
for (Method method2 : methods1) {
System.out.println(method2);
}
System.out.println("-----------------隔离线-----------------------");
// 获取指定公共方法
Method methodPublic = userClass.getMethod("insert", java.lang.String.class, java.lang.String.class);
System.out.println(methodPublic);
第三步:利用反射API操作探究信息
在第二步中我们已经可以获得了类的几个主要组成部分——属性、构造方法、方法各自的对象了,接下来我们就可以控制这些对象来完成一些操作了。
利用反射技术而进行的常用操作主要有三个:
通过Constructor创建对象
通过Method执行方法
通过Field为属性赋值取值
示例
通过反射实例化对象并使用对象:
/**
* 使用构造方法实例化对象
*
* @param <T> 返回对象
* @param o 构造参数列表
* @param userClass 传入一个类对象
* @return
*/
public static <T> T createObject(Class userClass, Object... o) {
// TODO Auto-generated method stub
try {
Constructor[] constructorArray = userClass.getConstructors();
int length = o.length;
for (Constructor constructor : constructorArray) {
Class[] claArray1 = constructor.getParameterTypes();
//构造方法的参数个数和传入的参数个数
if (claArray1.length == length) {
//将Object数组中的数据类型提出
Class[] oArray = dataConversion(o);
//将claArray1中含有的基本数据类型转化为包装类
Class[] claArray = dataConversion(claArray1);
for (int i = 0; i < length; i++) {
//比对数据类型是否相等
if (!claArray[i].getName().equals(oArray[i].getName())) {
throw new Exception("第" + (i + 2) + "个参数应该是" + claArray1[i].getName() + "类型的数据");
}
}
return (T) constructor.newInstance(o);
}
}
throw new Exception("没有该构造方法");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 将数组每个数据转化为对应类
* @param o
* @return
*/
public static Class[] dataConversion(Object[] o) {
Class[] cla = new Class[o.length];
int length = cla.length;
for (int i = 0; i < length; i++) {
cla[i] = o[i].getClass();
}
return cla;
}
/**
* 将基本数据转化为包装类
* @param c
* @return
*/
public static Class[] dataConversion(Class[] c) {
int length = c.length;
for (int i = 0; i < length; i++) {
if (c[i].getName().equals("byte")) {
c[i] = Byte.class;
}
if (c[i].getName().equals("char")) {
c[i] = Character.class;
}
if (c[i].getName().equals("short")) {
c[i] = Short.class;
}
if (c[i].getName().equals("int")) {
c[i] = Integer.class;
}
if (c[i].getName().equals("long")) {
c[i] = Long.class;
}
if (c[i].getName().equals("double")) {
c[i] = Double.class;
}
if (c[i].getName().equals("float")) {
c[i] = Float.class;
}
if (c[i].getName().equals("boolean")) {
c[i] = Boolean.class;
}
}
return c;
}
/**
* 调用方法
*/
public static void meth() {
// TODO Auto-generated method stub
try {
Class userClass = Class.forName("com.xxx.classroom.User");
Object c = createObject(userClass, 5L, "张", "ssss");
if (c != null) {
String userName = (String) userClass.getDeclaredField("userName").get(c);
String pwd = (String) userClass.getDeclaredField("password").get(c);
System.out.println("姓名:" + userName);
System.out.println("密码:" + pwd);
Long id = (Long) userClass.getDeclaredField("id").get(c);
System.out.println("id:" + id);
// 获取getPassword方法
Method method = userClass.getDeclaredMethod("getPassword");
// 使用方法
String s = (String) method.invoke(c);
System.out.println(s);
Method method2 = userClass.getDeclaredMethod("printNamePwd", int.class);
String str = (String) method2.invoke(c, 1);
System.out.println(str);
} else {
System.out.println("实例化对象失败");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
使用的user类:
public class User {
private static Long cc;
public Long id;
public String userName;
public String password;
String s;
public User() {
super();
}
/**
*
* @param id
* @param userName
* @param password
*/
public User(Long id, String userName, String password) {
super();
this.id = id;
this.userName = userName;
this.password = password;
}
public User(String userName, String password) {
super();
this.userName = userName;
this.password = password;
}
/**
* 获取密码
* @return
*/
public String getPassword() {
return password;
}
/**
* 获取名字密码
* @param i
* @return
*/
public String printNamePwd(int i) {
StringBuffer sb = new StringBuffer();
sb.append(this.userName);
sb.append(this.password);
sb.append(i);
return String.valueOf(sb);
}
private void insert(Long id) {
System.out.println("一个私有方法一个参数");
}
@Test
public void insert(String userName ,String pwd) {
System.out.println("这是一个共有的方法两个参数");
}
protected void insert(Long id,String userName ) {
System.out.println("这是一个受保护的方法两个参数");
}
}
更多方法参照JDK