Java基础之反射
一、什么是反射?
许多关于反射的讲解都是,在运行状态中,对于任意一个类,能知道他们的属性、构造方法、成员方法。对于任意一个对象,还能调用里面的一切方法和属性。假如有程序员A和程序员B,A想调用B写的类,但是B还没完成,A可以通过反射来修改或者查看B写的类有什么并且可以调用
二、反射是怎样实现的?
首先,必须获取Class字节码对象,用于表示.class文件,然后再解剖,解剖用的就是Class类中的方法,那有人可能要问了,为什么我不直接实例化一个对象来获取里面的信息呢,为什么要先获取Class对象,这不是麻烦吗?
三、反射与实例化对象的主要区别
1.运行时和编译时:反射是在运行时获取类信息和操作的机制,通过反射,我们可以不知道类的结构就对类进行查看以及一些操作,创建类的实例,调用方法,修改属性等,而直接实例化对象是在已知类的结构下完成的一些操作,在编译时就已经确定类的结构
2.灵活性与性能:反射可以动态地创建对象,调用方法等,但是性能较低,以为是在运行时期解析类信息,而直接实例化对象性能较高,因为它遵循正常的类加载和实例化流程
3.安全性:因为反射可以访问类的私有信息,这可能会破坏封装,而实例化对象只能允许访问公共方法
4.使用场景:反射大多数用在框架开发、动态代理等场景,而实例化对象说面向对象编程中最常用的方法
四、反射的常用方法
4-1、获取Class对象的三种方法
ublic class MyReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
/**
*
* 获取class对象的三种方式
* 1.Class.forName("全类名")
* 2.类名.class
* 3.对象.getClass()
*/
//1.第一种方式
//全类名:包名 + 类名
Class clazz1 = Class.forName("com.wjk.MyReflect1.Student");
//2.第二种方式
Class<Student> clazz2 = Student.class;
//3.第三种方式
Student s = new Student();
Class<? extends Student> clazz3 = s.getClass();
System.out.println(clazz1 == clazz2);
System.out.println(clazz2 == clazz3);
}
}
其中第一种是最常用的
4-2、Class类中用于获取构造方法的方法
public class MyReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/**
* Class类中用于获取构造方法的方法
* Constructor<?>[] getConstructors()
* Constructor<?>[] getDeclaredConstructors()
* Constructor<?>[] getConstructor(Class<?>...parameterTypes)
* Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes)
*
*
* Constructor类中用于创建对象的方法
* T newInstance(Object... initargs)
* setAccessible(boolean flag)
*/
//1.创建Class对象
Class clazz = Class.forName("com.wjk.MyReflect2.Student");
//2.获取所有构造方法
//2-1.获取所有的公共构造方法
// Constructor[] con1 = clazz.getConstructors();
// for (Constructor constructor : con1) {
// System.out.println(constructor);
// }
// System.out.println("------------------------");
// //2-2获取所有构造方法,包括私有
// Constructor[] con2 = clazz.getDeclaredConstructors();
// for (Constructor constructor : con2) {
// System.out.println(constructor);
// }
Constructor con1 = clazz.getDeclaredConstructor();
System.out.println(con1);
Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2);
Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
//3.获取权限修饰符
//public:1,private:2,protected:4,static:8
int modifiers = con3.getModifiers();
System.out.println(modifiers);
//在idea的底层用到了反射,根据权限修饰符判断修饰符类型,如果是私有的就不让你用
//4.获取参数
Parameter[] parameters = con3.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//创建对象
Student stu = (Student) con3.newInstance("wjk", 21);
System.out.println(stu);
//为什么报错?因为这个权限修饰符是私有的,DeclaredConstructor只是让我看见这个私有的构造方法啊,但不能直接使用
//如果要使用,必须setAccessible(true)
//暴力反射:表示临时取消权限校验
con3.setAccessible(true);
}
}
暴力反射:临时取消权限校验,因为是私有的,所以让他临时变成不是私有
4-3、Class类中用于获取成员变量的方法
public class MyReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
/**
* Class类中用于获取成员变量的方法
* Field[] getFields():返回所有公共成员变量对象的数组
* Field[] getDeclaredFields():返回所有成员变量对象的数组
* Field[] getField(String name):返回单个公共成员变量对象的数组
* Field[] getDeclaredField(String name):返回单个成员变量对象的数组
*
* Field类中用于创建对象的方法
* void set(Object,Object value):赋值
* Object get(Object obj):获取值
*/
//1.获取Class字节码文件的对象
Class<?> clazz = Class.forName("com.wjk.MyReflect3.Student");
//2.获取单个成员变量的值
Field name = clazz.getDeclaredField("name");
//3.获取权限修饰符
int modifiers = name.getModifiers();
//4.获取成员变量的名字
String n = name.getName();
System.out.println(n);
//5.获取成员变量的数据类型
Class<?> type = name.getType();
//6.获取成员变量记录的值
Student s = new Student("wjk",21);
//暴力反射
name.setAccessible(true);
String value = (String) name.get(s);
System.out.println(value);
//修改成员变量对象里面的值
name.set(s,"lisi");
}
}