反射机制的概念
由于对反射理解只停留在概念性的阶段,所以这篇文章只能简单的介绍下原理以及它的用法,java文件编译后变成class文件,也就是说java虚拟机实际上是运行的是class文件,在class文件中将java类中的各部分用它自己的方式进行表示,如一个java类中有方法,构造函数,变量,还有注解等等,这些东西,在java类中有Method,Filed,Constructor这三个类,在class文件中,有三个这样的数组分别是Method,Filed,Constructor的实例,我们用method,filed,constructor这三个变量表示,在method中包含了所有的方法,filed中包含了所有的变量,constructor中包含了所有的构造器函数,可以根据所有的 你传入的参数,方法名,变量名来进行判断你需要的是哪一个,并且动态的进行调用,获取(这些只是我本人看法,没经过验证,因为我还没有看过具体的class文件数据展示,而且这种机制我看别人的帖子总是很概念性的介绍,可能是我的知识量不够,觉得很空洞,苍白,所以以后再研究)
反射的用法
先定义一个类
import java.util.Date;
public class Person {
public String name="李四";
private int age = 18;
public static int sex=1;
public static Date date;
public Person(){
System.out.println("无参的构造函数");
}
private Person(int age){
System.out.println(age);
}
//构造函数可以有多个,但是参数的类型和个数,以及顺序必须不一样,
// 不然就会被默认为一样,如在下面的
protected Person(int age,String name,Date date){
System.out.println("获取保护类型的构造方法");
System.out.println(age);
System.out.println(name);
System.out.println(date);
}
public Person(String name)
{
System.out.println(name);
}
//参数个数相同
public Person(String name,int age)
{
System.out.println(name);
System.out.println(age);
}
public Person(int age,String name)
{
System.out.println(age);
System.out.println(name);
}
public void method1()
{
System.out.println("方法一");
}
public void method2(String name)
{
System.out.println("方法二"+name);
}
public void method3(int age)
{
System.out.println("方法三"+age);
}
public int method4(int age)
{
System.out.println("我是方法四");
return age;
}
public String method5(String name)
{
System.out.println("我是方法五");
return name;
}
private String method6(String sex)
{
System.out.println("我是方法6");
return sex;
}
private static void method7()
{
System.out.println("我是方法7");
}
protected static void method8()
{
System.out.println("我是方法7");
}
}
反射获取类的构造函数
/** * 获取构造方法,通过反射获取构造函数,主要是通过类所在的包名,获取到类的字节码对象(包名.类名) * 然后通过此类的字节码对象,调用获取构造函数的方法,并在方法里传入参数的字节码对象,在这里主要是通过 * 参数的个数,类型,和顺序,进行判断,筛选(一个类中可能有多个构造函数),具体判断顺序我没有测试过,但是,我个人感觉先判断参数 * 的个数,个数相同,看参数类型,类型可能有这样的一种情况,如(String,int)和(int,String),这就是两个不同的构造函数 * Class类中与Constructor相关的方法 1. Constructor getConstructor(Class... parameterTypes) * 根据参数类型获得对应的Constructor对象。 * 只能获得public修饰的构造方法 2. Constructor getDeclaredConstructor(Class... parameterTypes) * 根据参数类型获得对应的Constructor对象 * 可以是public、protected、(默认)、private修饰符的构造方法。 3. Constructor[] getConstructors() 获得类中的所有构造方法对象,只能获得public的 4. Constructor[] getDeclaredConstructors() 获得类中的所有构造方法对象 可以是public、protected、(默认)、private修饰符的构造方法。 */
package test_2021_1_5.反射;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.util.Date;
/**
* 获取构造方法,通过反射获取构造函数,主要是通过类所在的包名,获取到类的字节码对象(包名.类名)
* 然后通过此类的字节码对象,调用获取构造函数的方法,并在方法里传入参数的字节码对象,在这里主要是通过
* 参数的个数,类型,和顺序,进行判断,筛选(一个类中可能有多个构造函数),具体判断顺序我没有测试过,但是,我个人感觉先判断参数
* 的个数,个数相同,看参数类型,类型可能有这样的一种情况,如(String,int)和(int,String),这就是两个不同的构造函数
* Class类中与Constructor相关的方法
1. Constructor getConstructor(Class... parameterTypes)
* 根据参数类型获得对应的Constructor对象。
* 只能获得public修饰的构造方法
2. Constructor getDeclaredConstructor(Class... parameterTypes)
* 根据参数类型获得对应的Constructor对象
* 可以是public、protected、(默认)、private修饰符的构造方法。
3. Constructor[] getConstructors()
获得类中的所有构造方法对象,只能获得public的
4. Constructor[] getDeclaredConstructors()
获得类中的所有构造方法对象
可以是public、protected、(默认)、private修饰符的构造方法。
*/
public class demo01 {
@Test
//获取一个参数类型为String的构造函数
public void test01() throws Exception {
//1.获取字节码对象的第一种方式
Class aClass = Class.forName("test_2021_1_5.反射.Person");
//传入参数的字节码对象
Constructor constructor = aClass.getConstructor(String.class);
constructor.newInstance("张三");
}
@Test
//获取无参 的构造函数
public void test02() throws Exception{
Class aClass = Class.forName("test_2021_1_5.反射.Person");
//无参,所以参数类型为null
Constructor constructor = aClass.getConstructor(null);
//无参,传入null
constructor.newInstance(null);
}
@Test
//获取两个参数的构造函数,String,int
public void test03() throws Exception{
Class aClass = Class.forName("test_2021_1_5.反射.Person");
Constructor constructor = aClass.getConstructor(String.class, int.class);
constructor.newInstance("张三",15);
}
@Test
//获取两个参数的构造函数,int,String
public void test04() throws Exception{
Class aClass = Class.forName("test_2021_1_5.反射.Person");
Constructor constructor = aClass.getConstructor(int.class,String.class);
constructor.newInstance(15,"张三");
}
@Test
//获取私有的构造方法
public void test05() throws Exception{
Class aClass = Class.forName("test_2021_1_5.反射.Person");
// 注意:在反射私有的构造函数时,用普通的clazz.getConstructor()会报错,
// 因为它是私有的,所以提供了专门反射私有构造函数的方法 clazz.getDeclaredConstructor(int.class);
// 读取私有的构造函数,用这个方法读取完还需要设置一下暴力反射才可以
Constructor constructor = aClass.getDeclaredConstructor(int.class);
//获取私有的构造函数,必须进行暴力反射 ,设置"暴力反射"——是否取消权限检查,true取消权限检查,false表示不取消
constructor.setAccessible(true);
constructor.newInstance(20);
}
@Test
//获取protected类型的构造函数,需要暴力反射
public void test06() throws Exception
{
Class aClass = Class.forName("test_2021_1_5.反射.Person");
Constructor constructor = aClass.getDeclaredConstructor(int.class, String.class, Date.class);
constructor.setAccessible(true);
constructor.newInstance(15,"张三",new Date());
}
@Test
//一开始我们有可能并不知道参数有几个,顺序是什么,权限是什么,所以可以打印试一试
public void test07() throws Exception
{
Class aClass = Class.forName("test_2021_1_5.反射.Person");
//获取所有的公共的构造方法
Constructor[] constructors = aClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("===================");
//用getDeclaredConstructors[],可以获取所有的构造方法,包括私有的,保护的
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}
}
反射获取类的普通方法
/** * 通过反射获取类的方法 * * Method getMethod(String name,Class...args); * 根据方法名和参数类型获得对应的成员方法对象,只能获得public的 * Method getDeclaredMethod(String name,Class...args); 掌握 * 根据方法名和参数类型获得对应的成员方法对象,包括public、protected、(默认)、private的 * Method[] getMethods(); * 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的 * Method[] getDeclaredMethods(); 掌握 * 获得类中的所有成员方法对象,返回数组,只获得本类的,包括public、protected、(默认)、private */
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* 通过反射获取类的方法
* * Method getMethod(String name,Class...args);
* 根据方法名和参数类型获得对应的成员方法对象,只能获得public的
* Method getDeclaredMethod(String name,Class...args); 掌握
* 根据方法名和参数类型获得对应的成员方法对象,包括public、protected、(默认)、private的
* Method[] getMethods();
* 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
* Method[] getDeclaredMethods(); 掌握
* 获得类中的所有成员方法对象,返回数组,只获得本类的,包括public、protected、(默认)、private
*/
public class demo02 {
//实例出一个对象,直接调用,获取不到私有的和保护类型的方法
@Test
public void test01 () throws Exception
{
//第二种方式获取类的字节码对象
Class personClass = Person.class;
//获取一个无参的公共的类构造器
Constructor constructor = personClass.getConstructor();
//使用构造器创建一个实例
Person person =(Person) constructor.newInstance();
//使用实例去调用方法
person.method1();
person.method2("张三");
person.method3(15);
person.method4(20);
person.method5("王五");
}
//使用反射获取无参方法
@Test
public void test02() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//方法一没有参数,传null或者不传都可以
Method method = personClass.getMethod("method1");
//传入类的对象,和参数
method.invoke(p);
}
//使用反射获取有参方法
@Test
public void test03() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//传入方法的名字,和参数的字节码对象
Method method2 = personClass.getMethod("method2", String.class);
method2.invoke(p,"张三");
}
@Test
public void test04() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//传入方法的名字,和参数的字节码对象
Method method2 = personClass.getMethod("method3", int.class);
method2.invoke(p,15);
}
//使用反射获取返回值类型不为空的
@Test
public void test06() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//传入方法的名字,和参数的字节码对象
Method method2 = personClass.getMethod("method4", int.class);
int invoke =(int)method2.invoke(p, 15);
System.out.println(invoke);
}
//使用反射获取私有的方法
@Test
public void test07() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//传入方法的名字,和参数的字节码对象
Method method2 = personClass.getDeclaredMethod("method7");
//设置暴力反射
method2.setAccessible(true);
method2.invoke(p);
}
//使用反射获取所有的方法
@Test
public void test08() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//查询所有的方法
Method[] method2 = personClass.getDeclaredMethods();
for (Method method : method2) {
System.out.println(method);
}
System.out.println("===================================================");
//查询公共的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
反射获取类的变量
/** * 通过反射获取类的成员变量 * Class类中与Field相关的方法 * Field getField(String name); * 根据成员变量名获得对应Field对象,只能获得public修饰 * Field getDeclaredField(String name); * 根据成员变量名获得对应Field对象,包括public、protected、(默认)、private的 * Field[] getFields(); * 获得所有的成员变量对应的Field对象,只能获得public的 * Field[] getDeclaredFields(); * 获得所有的成员变量对应的Field对象,包括public、protected、(默认)、private的 */
import org.junit.Test;
import java.lang.reflect.Field;
import java.util.Date;
/**
* 通过反射获取类的成员变量
* Class类中与Field相关的方法
* Field getField(String name);
* 根据成员变量名获得对应Field对象,只能获得public修饰
* Field getDeclaredField(String name);
* 根据成员变量名获得对应Field对象,包括public、protected、(默认)、private的
* Field[] getFields();
* 获得所有的成员变量对应的Field对象,只能获得public的
* Field[] getDeclaredFields();
* 获得所有的成员变量对应的Field对象,包括public、protected、(默认)、private的
*/
public class demo03 {
@Test
//获取public属性
public void test01() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//获取name变量的的Field对象
Field name = personClass.getField("name");
//获取Filed对象的值
String o = (String)name.get(p);
System.out.println(o);
}
//获取private属性
@Test
public void test02() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//获取私有的变量的Filed对象
Field age = personClass.getDeclaredField("age");
//暴力反射
age.setAccessible(true);
//获取参数值
int o =(int) age.get(p);
System.out.println(o);
}
//设置静态变量的值
@Test
public void test03() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//获取私有的变量的Filed对象
Field date= personClass.getDeclaredField("date");
//设置变量的值
date.set(p,new Date());
System.out.println(Person.date);
}
//获取所有的变量
@Test
public void test04() throws Exception{
Class personClass = Person.class;
Person p = (Person)personClass.newInstance();
//获取私有的变量的Filed对象
Field[] fields= personClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("===================================================================");
//获取public
Field[] fields1 = personClass.getFields();
for (Field field : fields1) {
System.out.println(field);
}
}
}