有同样被被反射折磨的吗?不知道反射怎么理解,以及注解怎么用,希望这篇文章可以帮助到你
反射
1.1反射的概述
是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。
由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
1.2获取Class对象的三种方式
- 类名.class
- 对象名.getClass()方法
- Class.forName(全类名)方法
1.2.2 示例代码
//首先自己得有个Student对象
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//使用类的class属性来获取该类对应的Class对象
Class<Student> c1 = Student.class;
System.out.println(c1);
Class<Student> c2 = Student.class;
System.out.println(c1 == c2);
System.out.println("--------");
//调用对象的getClass()方法,返回该对象所属类对应的Class对象
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1 == c3);
System.out.println("--------");
//使用Class类中的静态方法forName(String className)
//全类名:就是包名.类名
Class<?> c4 = Class.forName("test.Student");
System.out.println(c1 == c4);
}
}
1.3 反射获取构造方法并使用
1.3.1Class类获取构造方法对象的方法
方法名 | 说明 |
Constructor<?>[] getConstructors() | 返回所有公共构造方法对象的数组 |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造方法对象的数组 |
Constructor getConstructor(Class<?>... parameterTypes) | 返回单个公共构造方法对象 |
Constructor getDeclaredConstructor(Class<?>...parameterTypes) | 返回单个构造方法对象 |
1.3.2Constructor类用于创建对象的方法
方法名 | 说明 |
T newInstance(Object...initargs) | 根据指定的构造方法创建对象 |
1.4 反射获取构造方法并使用练习
/*
通过反射来对对象进行复制:
1.先获取一个class对象;
2,获取一个对应的构造函数,构造函数的参数是
想要进行构造数据类型对应的字节码文件对象,通过getDeclaredConstructor方法进行获取,记得
参数是是你想要进行使用构造函数的参数类型.class
3,构造对象,通过newInstance(),进行构造函数,括号中是要进行设置的值,与上面获取的构造函数
要进行相匹配,类型和个数一定要一致
*/
public class MyConstructors {
public static void main(String[] args) throws Exception {
//获取class对象
Class<Student> studentClass = Student.class;
//参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象
//获得对应的构造函数
Constructor<Student> con = studentClass.getDeclaredConstructor(String.class,int.class);
con.setAccessible(true);//进行暴力反射
//用newInstance进行设置值
Student stu = con.newInstance("哈哈", 12);
System.out.println(stu);
System.out.println("-----------------");
//这是空构造函数
Student stu1 = studentClass.newInstance();
System.out.println(stu1);
}
}
注意:1.要获得对应的构造函数,这个构造函数必须是之前的类中定义有的,我的Student类中定义的有相应的构造函数。
2.使用带Declared的函数,一定记得要暴力反射
1.5反射获取成员变量并使用
1.5.1 class类获取成员变量对象的方法
方法名 | 说明 |
Field[] getFields() | 返回所有公共成员变量对象的数组 |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组 |
Field getField(String name) | 返回单个公共成员变量对象 |
Field getDeclaredField(String name) | 返回单个成员变量对象 |
1.5.2 Field类用于给成员变量赋值的方法
方法名 | 说明 |
voidset(Object obj,Object value) | 给obj对象的成员变量赋值为value |
1.5.2 反射获取成员变量并使用
/*
对成员变量进行赋值的步骤:
1,先获取一个class对象
2,再确定要进行赋值的变量名getDeclaredField(),参数就是用来指定是要给哪个
成员变量进行复制
3,进行给成员变量进行复制,在赋值之前必须先有对象,因为成员变量是通过对象进行调用的,
然后再调用set()函数,对成员变量进行复制
要改变的变量.set(对象,要进行赋的值)
*/
public class MyField {
public static void main(String[] args) throws Exception {
//获取class对象
Class<Student> studentClass = Student.class;
//要确定是对那个成员变量进行复制
//得到要进行被更改的成员变量
Field name = studentClass.getDeclaredField("name");
name.setAccessible(true);//进行暴力反射
//在确定要更改哪个成员变量之后,要对变量进行赋值,在赋值之前,要先得到对象,
//因为成员变量是通过对象进行调用的
//构造函数
Student student = studentClass.newInstance();
name.set(student,"哈哈");
System.out.println(student);
}
}
1.6 反射获取成员方法并使用
1.6.1 Class类获取成员方法对象的方法
方法名 | 说明 |
Method[] getMethods() | 返回所有公共成员方法对象的数组,包 括继承的 |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,不包括继承的 |
Method getMethod(String name, Class<?>...parameterTypes) | 返回单个公共成员方法对象 |
Method getDeclaredMethod(String name, Class<?>...parameterTypes) | 返回单个成员方法对象 |
1.6.2 方法用于执行方法的方法
方法名 | 说明 |
Objectinvoke(Object obj,Object... args) 1 | 用obj对象的成员方法,参数是args,返回值是Object类型 |
1.6.3 反射获取成员函数的使用
//总结通过反射进行调用成员方法
/*
1.先获取Class对象
2.要确定是要调用哪个方法 getMethod("成员方法的名称",参数类型.class)
3. 在运行方法之前得先有对象,成员方法是通过对象进行调用的,
然后运行方法 invoke
格式:要调用的方法.invoke(对象,要进行传递的参数)
*/
//注意:如果调用的是有有参,有返回值得成员函数,调用参数在指定有参是在getMethod函数中,进行指定
// 要调用的成员函数的名称,以及成员函数的参数的类型.class,有返回值得话,返回就好,在调用方法的时候,
// invoke的时候要填上对应的参数
public class MyMethod02 {
public static void main(String[] args) throws Exception {
//案例要求:通过反射调用方法并反射
//1.成员方法是无参无返回值
//获取class对象
Class<Student> studentClass = Student.class;
//获取要调用的方法
Method eatMethod = studentClass.getMethod("eat");
//获取无参构造方法创建对象
Student student = studentClass.newInstance();
//在调用方法之前,得先有对象,是通过对象,进行调用方法的
//运行方法
eatMethod.invoke(student);
//2.有参无返回值
//先获取class对象
//确定要获取哪个成员方法
Method eat1 = studentClass.getMethod("eat1", String.class);
//创建对象
Student student2= studentClass.newInstance();
//调用方法
eat1.invoke(student2,"哈哈");
//3.成员方法有参有返回值
//通过什么样的构造方法进行调用成员函数是没有影响的
Method sleep = studentClass.getMethod("sleep",String.class);
//获取对象,通过有参的构造方法进行构造是不影响结果的,因为我们是执行成员函数,与构造函数没有关系
// Constructor<?> constructor= studentClass.getConstructor(String.class);
// Object obj = constructor.newInstance("嘻嘻");
Object invoke = sleep.invoke(student,"eenheng");
System.out.println(invoke);
}
}
注意:1.使用什么样的构造函数进行调用方法是不影响结果的,我们是要执行成员函数,与构造函数无关
2.使用什么样的成员方法,在进行获取的时候一定要对应
1.7 反射的应用
应用一:
//通过反射,向一个泛型为Integer的集合中添加一些字符串
public class ReflectDemo01 {
public static void main(String[] args) throws Exception {
ArrayList<Integer> arrayList=new ArrayList<>();
Class<? extends ArrayList> aClass = arrayList.getClass();
Method add = aClass.getMethod("add", Object.class);
ArrayList arrayList1 = aClass.newInstance();//获取对象
add.invoke(arrayList1,new Student("哈哈",15));
System.out.println(arrayList1);
}
}
应用二:
下面是配置文件的内容:
//案例要求:通过反射运行配置文件中指定类的指定方法
public class ReflectDemo02 {
public static void main(String[] args) throws Exception {
//加载数据
//Properties存储的键值对就是String ,String
Properties pro = new Properties();
FileReader fr=new FileReader("study_study\\src\\Pro.properties");
//load直接就把文件中的内容存储到Properties对象上了
pro.load(fr);
fr.close();
//进行分别获取键值对的数据
//通过键得到值
String className = pro.getProperty("className");//这是全类名
String methodName = pro.getProperty("methodName");//这是方法名
Class<?> aClass = Class.forName(className);
Object o = aClass.newInstance();
Method method = aClass.getMethod(methodName);
method.invoke(o);
}
}
看了以上两个应用,相信大家对反射有了一定的理解吧,是不是和我一样觉得反射很神奇。。。。。。。。。。。。