反射
框架
->半成品软件
->灵魂
-> 反射
前言
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) {
//遍历快捷键iter
System.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;
}
@Override
public 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.forName
BytecodeDescriptor
ClassLoader.loadClass
sun.reflect.misc.MethodUtil
sun.reflect.misc.FieldUtil
sun.reflect.misc.ConstructorUtil
MethodAccessor.invoke
JSClassLoader.invoke
JSClassLoader.newInstance