反射是一个很重要的技术,通过反射技术,能把多个成分构建成一个Java类,话不多说,开始介绍。
Class类
Class类是一个比Object类还抽象的应该东西,在POJO里面,Object表示所有的东西,而Class表示这些所有定义对象的类文件,可以理解为Class的实例对象,表示定义对象的字节码,Class就是Java的类的抽象。
Class是不能用new来创建的,有三种获得Class实例的方法,分别如下
Class a = String.class;
Class b = "abc".getClass();
Class c = Class.forName("java.lang.String");
特殊
有9个预定义的Class对象
byte.class == Byte.TYPE;
short.class == Short.TYPE;
int.class == Integer.TYPE;
long.class == Long.TYPE;;
float.class == Float.TYPE;
double.class == Double.TYPE;
char.class == Character.TYPE;
double.class == Double.TYPE;
boolean.class == Blooean.TYPE;
void.class == Void.TYPE;
原始类型都有各自的Class
Class中有 isPrimitive() 方法来判断类是否为原始类型
isArray() 判断是否为数组
Constructor类
代表类的构造器
Class strcla = Class.forName("java.lang.String");
//获取所有的类的构造器
Constructor[] acs = strcla.getConstructors();
//获取参数是StringBuffer的构造器
Constructor ac = strcla.getConstructor(StringBuffer.class);
// 利用构造器,创建对象
String a = (String) ac.newInstance(new StringBuffer("666"));
这些方法需要捕获异常
有些构造器是私有的,不能被直接获取到,可以暴力反射
public class Demo02 {
private Demo02(){
System.out.println("hahaha");
}
}
public class Demo01 {
public static void main(String [] args) throws Exception {
//获取字节码
Class demo02 = Demo02.class;
//获取私有构造器
Constructor c = demo02.getDeclaredConstructor();
//取消访问权限检查
c.setAccessible(true);
//执行构造器
c.newInstance();
}
}
Method类
方法
public class Demo02 {
private String secretFunc(String name,String desc) {
System.out.println(name);
System.out.println(desc);
return name + "做了一把" + desc;
}
}
访问Demo02实例的secretFunc方法
class Demo01 {
public static void main(String [] args) throws Exception {
Class dclass = Demo02.class;
//获取secretFunc方法
Method method = dclass.getDeclaredMethod("secretFunc",String.class,String.class);
//实例一个demo02
Demo02 demo02 = new Demo02();
//去掉权限验证(暴力反射)
method.setAccessible(true);
//执行demo02的secretFunc方法,并获得返回值
String result = (String) method.invoke(demo02,"罗永浩","锤子");
//输出结果
System.out.println(result);
}
}
有些方法只知道名字,不知道参数,可以用getMethods()
先取出所有方法,再一一用,getParameters()
来获得参数类型。
具体可以去查阅API文档
Field类
属性(成员变量)
可以用来访问私有变量,修改变量值
public class Demo02 {
private String XXX = "day day up";
}
修改私有成员变量
class Demo01 {
public static void main(String [] args) throws Exception {
Class dclass = Demo02.class;
//获取XXX成员变量
Field xxx = dclass.getDeclaredField("XXX");
//实例一个demo
Demo02 demo02 = new Demo02();
//去掉权限验证(暴力反射)
xxx.setAccessible(true);
//获取这个属性的值
System.out.println(xxx.get(demo02));
//修改demo02的XXX属性
if(xxx.getType()==String.class){
xxx.set(demo02,"good good study");
}
System.out.println(xxx.get(demo02));
}
}
使用场景
在搭建框架的时候,有时候不知道需要什么类,什么方法,这个类有哪些属性。比如查询数据库之后的数据,反射成对象。
比如
- 现在在配置文件中,定义了要使用的类
com.User
- 我们在数据库里查询到了一个数据(这里用JSON字符串来代替)
- 我们根据配置,把这组数据,转换成配置中的对象
progress方法是框架定义好的方法,之前读取配置和查询数据库分别被我简化了
/**
* 简化读取配置
*/
public String getProfileData() {
return "com.User";
}
/**
* 简化数据库查询(用JSON代替了,JDBC其实也可以)
*/
public String getDataFromDatabase() {
return "{\"address\":\"小米街道\",\"name\":\"雷军\",\"sex\":\"unknown\"}\n";
}
@Test
public void progress() throws Exception {
//读取配置得到对象配置
Class useClass = Class.forName(getProfileData());
//实例化对象
Object needObj = useClass.newInstance();
//读取数据库,获得数据
JSONObject datas = JSON.parseObject(getDataFromDatabase());
//获取参数名称集合
Set<String> keys = datas.keySet();
for (String key : keys) {
//调用set方法
Method md = useClass.getMethod("set" + StringUtils.capitalize(key), String.class);
md.invoke(needObj, datas.get(key));
}
// 这就得到了需要的对象
System.out.println(needObj);
}
定义好User
package com;
/**
* Created by zing on 2016/11/10.
*/
public class User {
private String name;
private String address;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User对象:\n" +
"名字='" + name + "\'\n" +
"地址='" + address + "\'\n" +
"性别='" + sex + "\'\n" ;
}
}
这两段代码都搞定之后,执行progress方法就可以了。
很明显,接下来包装一下的话,就可以写一个自己的持久层框架了。
当然反射的用处不止这些,我们还可以用这个来调用系统的私有方法,Android要是读过源码的话,很多流氓的东西很容易就干出来了(我不是说C++层的),我就不细说了。
回来
ps:别在意数据,重点在技术
love&peace