反射
反射即反向探知,比如考古学家根据发掘的物品来探知以前的事情。
指在Java程序运行状态中,
1,对于给定的一个类(Class)对象,可以获得这个类(Class)对象的所有属性和方法;
2,对于给定的一个对象,能够调用它的任意一个属性和方法。
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制。就叫做JAVA的反射机制。
Class clazz = Person.class
//获取一个实例对象
Person person = clazz.newInstance();
// 获取类型中的方法
Method method = clazz.getDeclaredMethod("run");
// 通过反射执行方法
method.invoke(person);
反射的优缺点
优势
增加程序的灵活性,避免将固有的逻辑程序写死到代码里
代码简洁,可读性强,可提高代码的复用性
缺点
相较直接调用在量大的情景下反射性能下降
内部暴露和安全隐患
反射到底慢在哪些地方
需要调用native方法
每次newInstance(),都会做安全检查
寻找类Class字节码的过程
反射的基本操作
获取类对象,四种
Class<User> clazz1 = User.class;
Class<?> clazz2 = Class.forName("com.fs.User");
Class<? extends User> clazz3 = new User().getClass();
Class<?> clazz4 = Demo.class.getClassLoader().loadClass("com.fs.User");
获取类的基本信息
// 获取类的相关结构
clazz1.getModifiers(); //获取类的修饰符1025=1+1024=public abstact
clazz1.getPackage();//包名
clazz1.getName();//类全名
clazz1.getSuperclass();//父类
clazz1.getClassLoader();//类加载器
clazz1.getSimpleName();//简单名称
clazz1.getInterfaces(); // 获取类实现的所有的接口
clazz1.getAnnotations();//获取类的所有注解
修饰符 八位二进制数字表示
获取类的字段
// 获取类中定义共有的字段,以及父类中共有的字段
Field[] fields1 = clazz.getFields();
// 可以获取私有的字段 只能够获取当前类中
Field[] fields2 = clazz.getDeclaredFields();
// 获取指定名称Field
Field nameField = clazz.getDeclaredField("name");
// 如果要修改私有属性信息那么我们需要放开权限
nameField.setAccessible(true);
nameField.set(user,"AJ");
// 对静态属性赋值
nameField.set(null,"HN");
类的方法操作
// 获取类以及父类中的共有的方法
Method[] methods = clazz.getMethods();
// 获取类中的方法,包括私有的
Method[] declaredMethods = clazz.getDeclaredMethods();
// 获取类中指定名称的方法
Method run1 = clazz.getDeclaredMethod("run");
// 放开私用方法执行
run.setAccessible(true);
run1.invoke(user);
// 获取类中指定名称和参数的方法
Method run = clazz.getMethod("run", String.class);
// 静态方法调用
run.invoke(null,"777");
类的构造器操作
//获取类中所有的公有构造器
Constructor[] cons = clazz.getConstructors();
//获取类中所有的构造器
Constructor[] cons1 = clazz.getDeclaredConstructors();
//class直接调用默认无参构造
Person.class.newInstance();
//获取类中无参的构造器
Constructor conNoParam= clazz.getDeclaredConstructor();
conNoParam.newInstance(); //构造器实例对象
//获取类中有参构造
Constructor con = clazz.getDeclaredConstructor(String.class);
con.setAccessible(true); //私用的构造器放开权限
con.newInstance("abc");//有参构造调用
破局反射破坏单例
原因:反射可以调用类中私用的构造器
解决方案:在私用构造器中加入逻辑判断
if(Single.instance !=null){
throw new RunTimeException("实例已经创建了");
}
反射的使用场景
SpringIOC
Mybatis
JDBC