什么叫反射?
当一个字节码文件加载到内存的时候,jvm会对该字节码进行解剖,然后会创建一个对象的Class对象,把字节码文件的信息全部都存储到该Class对象中,我们只要获取到Class对象,我们就可以使用字节码对象设置对象的属性或者调用对象的方法等操作
在反射技术中一个类的任何成员都有对应 的类进行描述。 比如: 成员变量(Field) 方法 Method类
下面我们新建一个Student类进行测试
/**
* 学生
*
* @author evan_qb
*/
public class Student {
String name;
String age;
public Student(String name) {
this.name = name;
}
private Student() {
}
private static void study(){
System.out.println("学习");
}
private void smoke(int num) {
System.out.println("抽" + num + "根烟");
}
public void sleep() {
System.out.println("睡觉");
}
public void eat(int num) {
System.out.println("吃" + num + "两饭");
}
}
使用放射获取类的Class对象的方式:
//获取对象的第一种方式 常用这种
Class clazz1 = Class.forName("cn.qblank.reflect.Student");
System.out.println("第一种方式:" + clazz1);
//获取对象的第二种方式
Class clazz2 = Student.class;
System.out.println("第二种方式:" + clazz2);
//获取对象的第三种方式
Class clazz3 = new Student("张三").getClass();
System.out.println("第三种方式:" + clazz3);
通过Class对象获取构造方法
/**
* 通过Class对象获取构造方法
* @author Administrator
*
*/
public class ReflectDemo2 {
public static void main(String[] args) {
try {
Class clazz = Class.forName("cn.qblank.reflect.Student");
//获取该类下的所有公共的构造方法
Constructor[] constructors = clazz.getConstructors();
System.out.println("获取公共构造方法");
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获取该类下的所有构造方法(包括私有的)
Constructor[] dcons = clazz.getDeclaredConstructors();
System.out.println("获取所有构造方法");
for (Constructor constructor : dcons) {
System.out.println(constructor);
}
//获取单个指定的构造方法 如果构造方法是有参数的则加上参数类型.class 无参则传入空值
System.out.println("获取单个指定的构造方法");
Constructor con = clazz.getConstructor(String.class);
//创建一个对象
Student stu = (Student)con.newInstance("张三");
System.out.println(stu.name);
//获取单个指定的私有构造方法
System.out.println("获取单个指定的私有构造方法");
Constructor c = clazz.getDeclaredConstructor(null);
//设置允许访问私有的构造方法
c.setAccessible(true);
Student stu1 = (Student)c.newInstance(null);
System.out.println(stu1.name);
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过Class对象获取到对应的方法并调用:
/**
* 通过Class对象获取到对应的方法并调用。
* 在反射技术中使用了Method类描述了方法的。
* @author evan_qb
*
*/
public class ReflectDemo3 {
public static void main(String[] args) {
try {
//获取到对应的Class字节码类对象
Class clazz = Class.forName("cn.qblank.reflect.Student");
//和获取构造方法的方式类似
Method[] methods = clazz.getMethods();
System.out.println("----------获取该类下的所有公共方法(包括父类的方法)----------");
for (Method method : methods) {
System.out.println(method);
}
System.out.println("----------获取该类下的所有方法(不包括父类)----------");
Method[] dmethods = clazz.getDeclaredMethods();
for (Method method : dmethods) {
System.out.println(method);
}
//获取单个指定的方法 如果方法是有参数的则加上参数类型.class 无参则传入空值
System.out.println("----------获取该类下的指定的公共方法----------");
Method m1 = clazz.getMethod("eat", int.class);
//调用方法(非静态方法) invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。
//创建一个对象
Constructor con = clazz.getConstructor(String.class);
Student stu = (Student) con.newInstance("李四");
//调用方法并传入参数
m1.invoke(stu, 3);
System.out.println("----------获取该类下的指定的方法----------");
Method m2 = clazz.getDeclaredMethod("smoke", int.class);
//设置访问权限
m2.setAccessible(true);
//调用方法(非静态方法) invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。
//创建一个对象
Constructor con2 = clazz.getConstructor(String.class);
Student stu2 = (Student) con2.newInstance("王五");
//调用方法并传入参数
m2.invoke(stu2, 7);
//调用静态方法就只要将invoke的第一个参数即调用者设为空即可
System.out.println("----------获取该下的指定的静态方法----------");
Method m3 = clazz.getDeclaredMethod("study", null);
//设置访问权限
m3.setAccessible(true);
//调用方法(非静态方法) invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。
//创建一个对象
Constructor con3 = clazz.getDeclaredConstructor(null);
//设置私有的构造方法的访问权限
con3.setAccessible(true);
Student stu3 = (Student) con3.newInstance();
//调用方法并传入参数
m3.invoke(null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果如下:
获取成员变量
/**
* 获取成员变量
* @author Administrator
*
*/
public class ReflectDemo4 {
public static void main(String[] args) {
try {
//获取Class对象
Class clazz = Class.forName("cn.qblank.reflect.Student");
//获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
System.out.println("----------获取所有成员变量----------");
for (Field field : fields) {
System.out.println(field);
}
System.out.println("----------获取指定的成员变量----------");
Field dField = clazz.getDeclaredField("name");
dField.setAccessible(true);
//创建一个对象
Constructor constructor = clazz.getDeclaredConstructor(null);
//设置构造方法的访问权限
constructor.setAccessible(true);
Student student = (Student)constructor.newInstance(null);
dField.set(student, "马六");
System.out.println(student.name);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果如下:
由此可见反射的功能还是非常强大的,但实现起来却是比较麻烦,但java的框架基本上都是用这个写的,所以就算是再麻烦,也是需要学习学习的