反射
框架 ->半成品软件 ->灵魂 -> 反射
前言
java安全从反序列化漏洞说起,反序列化漏洞从反射开始说起
反射是大多数语言都必不可少部分
对象可以通过反射获取他的类,类可以通过反射拿到所有方法(包括私有),拿到的方法可以调用
总之通过反射,我们可以将Java这个静态语言附加上动态特性
简介
反射机制:
将类的各个组成部分分装为其他对象
好处
- 在程序的运行过程中,去操作这些对象
- 可以解耦,提高程序的可扩展性
获取class对象的三种方式
- Source源代码阶段:
第一阶段,java代码只有字节码文件,并没有进入到内存
需要手动的加载进内存,生成class对象
多用于配置文件,将类名定义在配置文件中,读取文件,加载类
class.forName("全类名") //将字节码文件加载进内存,返回class对象
package live.yanmu.domain;public class res1 {public static void main(String[] args) throws Exception {Class aClass = Class.forName("live.yanmu.domain.dd.person");System.out.println(aClass);}}
- Class类对象阶段
已经加载进内存了,只是并没有获取到它
多用于参数的传递
类名.class
package live.yanmu.domain;import live.yanmu.domain.dd.person;public class res1 {public static void main(String[] args) throws Exception {Class<person> personClass = person.class;System.out.println(personClass);}}
- Runtime运行时阶段
已经有person对象了
用object对象的方法来获取
多用于对象的字节码方式
对象.getclass()
package live.yanmu.domain;import live.yanmu.domain.dd.person;public class res1 {public static void main(String[] args) throws Exception {person person = new person();Class aClass = person.getClass();System.out.println(aClass);}}
比较
同一个字节码文件,在一次程序的运行过程中,只会被加载一次,不论是通过什么方式的class对象都是同一个
使用
获取的功能
- 获取成员变量们
- Field[] getFields()
- Field getField(String name)
- Field[] getDeclaredFields()
- Field getDeclaredField(String name)
- 获取构造方法们
- Constructor<?>[] getConstructors()
- Constructor getConstructor(类…parameterTypes)
- Constructor getDeclaredConstructor(类…parameterTypes)
- Constructor<?>[] getDeclaredConstructors()
获取成员方法们
|方法[]|getMethods()| | —- | —- | |方法[]|getDeclaredMethods()| |方法|getMethod(String name, 类<?>... parameterTypes)| |方法|getDeclaredMethod(String name, 类<?>... parameterTypes)|获取类名
- String getName()
Field:成员变量
- 操作
- 设置值
set(Object obj,Object value) - 获取值
get(Object obj)
- 设置值
代码演示
package live.yanmu.domain;import live.yanmu.domain.dd.person;import java.lang.reflect.Field;public class res1 {public static void main(String[] args) throws Exception {Class personClass = person.class;//获取所有public修饰的成员变量的Field[] fields = personClass.getFields();for (Field field : fields) {//遍历快捷键iterSystem.out.println(field);}System.out.println("---------------------");//获取指定public的成员变量Field a = personClass.getField("a");//获取成员变量a的值person person = new person();Object o = a.get(person);System.out.println(o);a.set(person,3);System.out.println("-------------------------");System.out.println(person);System.out.println("=======================================");//获取所有的成员变量,不考虑什么修饰符Field[] declaredFields = personClass.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println(declaredField);}//在使用不是public修饰符修饰的时候Field d = personClass.getDeclaredField("d");//忽略安全权限修饰符检测//home转到光标最前面,end转到最后面//暴力反射d.setAccessible(true);Object o1 = d.get(person);System.out.println(o1);}}
package live.yanmu.domain;import live.yanmu.domain.dd.person;import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class res1 {public static void main(String[] args) throws Exception {Class personClass = person.class;//获取构造方法->创建对象Constructor constructor = personClass.getConstructor(String.class, int.class);System.out.println(constructor);Object yanmu = constructor.newInstance("yanmu", 11);System.out.println(yanmu);//也可以用空参的构造创建对象//constructor.setAccessible(true);}}
package live.yanmu.domain;import live.yanmu.domain.dd.person;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class res1 {public static void main(String[] args) throws Exception {Class personClass = person.class;//获取指定名称的方法Method eat = personClass.getMethod("eat");person person = new person();//执行空参方法eat.invoke(person);Method eat1 = personClass.getMethod("eat", String.class);//执行有参方法eat1.invoke(person,"饭");System.out.println("=========================");//获取所有public修饰的方法Method[] methods = personClass.getMethods();for (Method method : methods) {//含有object里面的方法System.out.println(method);System.out.println(method.getName());// method.setAccessible(true);}}}
package live.yanmu.domain.dd;public class person {private String name;private int age;public int a;protected int b;int c;private int d;public person(){}public person(String name, int age) {this.name = name;this.age = age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return "person{" +"name='" + name + '\'' +", age=" + age +", a=" + a +", b=" + b +", c=" + c +", d=" + d +'}';}public void eat(){System.out.println("eat........");}public void eat(String aaa){System.out.println("你喜欢吃"+aaa);}}
相关面试题
JAVA 反射做了什么事情
反射是根据字节码获取类的信息或调用方法
从开发者角度来讲,反射最大意义是提高程序的灵活性
Java本身是一个静态语言,但反射特性允许运行时动态修改类的定义和属性等,达到动态效果
JAVA反射可以修改Final字段吗
可以做到
主要是用到setAccessible功能
//也叫做暴力反射xx.setAccessible(true)
传统反射方法加入黑名单怎么绕过
可以使用多种类和方法
ReflectUtil.forNameBytecodeDescriptorClassLoader.loadClasssun.reflect.misc.MethodUtilsun.reflect.misc.FieldUtilsun.reflect.misc.ConstructorUtilMethodAccessor.invokeJSClassLoader.invokeJSClassLoader.newInstance
