前言
上一次看java反射还是在java核心技术里面看的,当时不知道干嘛用的,现在又遇见了,再学习一次,通过实例来记录,方便以后拾遗.
原理
java反射就是将内存中的字节码封装成Class对象,加载之后再对里面的内容进行剖析的这样的一个过程
流程
- class.forname()获得class对象,你要剖析哪个类?
- get获得你想要的部分,可能是构造器,可能是方法,可能是field.
- 如果是私有的,你需要设置setAccessible,这样你才有私有的访问权限
- 进行操作,方法()调用,构造器构造实例,field进行读写
实例
package reflect;
public class Student {
private String name;
private int grade;
private static final String words = "hu hu";
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", grade=" + grade +
'}';
}
public Student() {
}
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
private Student(String name){
this.grade = 10;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
private void say(String text){
System.out.println(text+"成功");
}
public void sleep() {
System.out.println("睡觉zzz");
}
public static void sleep(String words) {
System.out.println("睡觉的时候打" + words);
}
public static void main(String[] args) {
System.out.println("main方法");
}
public void work(String[] kouhao, int[] number, String name) {
System.out.println(name + "正在工作" + kouhao + number);
}
}
对里面的内容进行剖析
package reflect;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
public class Demo {
/**
* 解析无参数的构造函数
*
* @throws Exception
*/
@Test
public void reflect1() throws Exception {
Class clazz = Class.forName("reflect.Student");
Constructor constructor = clazz.getConstructor();
Student student = (Student) constructor.newInstance();
System.out.println(student.toString());
}
/**
* @throws Exception public Student(String name, int grade)
* 有参数的构造器
*/
@Test
public void reflect2() throws Exception {
Class clazz = Class.forName("reflect.Student");
Constructor constructor = clazz.getConstructor(String.class, int.class);
Student student = (Student) constructor.newInstance("张三", 96);
System.out.println(student.toString());
}
/**
* @throws Exception private Student(String name)
* 私有构造器
*/
@Test
public void reflect3() throws Exception {
Class clazz = Class.forName("reflect.Student");
// 构造器是私有的加上declared
Constructor constructor = clazz.getDeclaredConstructor(String.class);
// 因为是私有的所以要设置accessiable
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance("李四");
System.out.println(student.toString());
}
/**
* @throws Exception public void sleep()
* 无参数的实例方法
*/
@Test
public void reflect4() throws Exception {
Class clzz = Class.forName("reflect.Student");
Method method = clzz.getMethod("sleep");
Student student = new Student();
method.invoke(student);
}
/**
* @throws Exception public static void sleep(String words)
* 带有一个参数的方法
*/
@Test
public void reflect5() throws Exception {
Class clzz = Class.forName("reflect.Student");
Method method = clzz.getMethod("sleep", String.class);
Student student = new Student();
method.invoke(student, "sleep");
}
/**
* @throws Exception public void work(String[] kouhao, int[] number, String name)
* 多个复杂类型的方法
*/
@Test
public void reflect6() throws Exception {
Class clazz = Class.forName("reflect.Student");
Method method = clazz.getMethod("work", String[].class, int[].class, String.class);
method.invoke(new Student(), new String[]{"1", "2", "3"}, new int[]{1, 2, 3}, "你好");
}
/**
* @throws Exception public String getName
* 有返回值,没有参数
*/
@Test
public void reflect7() throws Exception {
Class clazz = Class.forName("reflect.Student");
Method method = clazz.getMethod("getName");
String result = (String) method.invoke(new Student());
System.out.println(result);
}
/**
* @throws Exception private void say(String text)
* 私有的带参数没有返回值的方法
*/
@Test
public void reflect8() throws Exception {
Class clazz = Class.forName("reflect.Student");
Method method = clazz.getDeclaredMethod("say", String.class);
method.setAccessible(true);
method.invoke(new Student(), "1s");
}
/**
* @throws Exception main
*/
@Test
public void reflect9() throws Exception {
Class clazz = Class.forName("reflect.Student");
Method method = clazz.getDeclaredMethod("main", String[].class);
method.setAccessible(true);
/*
注意:java.lang.IllegalArgumentException: wrong number of arguments
这里 为什么要把new String[]数组转换成对象,是因为jdk1.5有可变参数,而jdk1.4旧版本没有
invoke(Object obj, Object ... args) 1.5
invoke(OBject obj, Object[] args) 1.4
不加的时候会把"2" 当做一个参数, "4"当成一个参数去找main(String str1, String str2)这个方法,
而不是找main(String[] args) 这个数组对象为参数的方法
*/
method.invoke(new Student(), (Object) new String[]{"2", "4"});
}
/**
* @throws Exception
* 通过反射对field的get和set操作
*/
@Test
public void reflect10() throws Exception {
Class clazz = Class.forName("reflect.Student");
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
Student student = new Student();
field.set(student, "张三");
String result = (String) field.get(student);
System.out.println(result);
}
}
总结
1.为什么要有反射?反射是为框架做的铺垫,各种框架都是用到了反射
2.反射如果要对私有的方法/field进行剖析就得设置访问权限setAccessible(true);
3.你需要给出完整的包的名称”包.类”这样