反射(框架实现的基础)
什么是反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制(注意关键词:运行状态)换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods
反射:将类的各个组成部分封装为其他对象,反射机制
这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制
疑惑:就是真的要每一个请求都写一个Servlet去接收吗?那不是很麻烦?一个是类多,同一放在了web包管理起来很难(当时想的一个效果就是能不能用一个Servlet去接收全部的请求,而且这个Servlet有全部请求得处理方法)
写的这个mvc
:想实现一个目的地,就是要简单,方便得解决上面得问题
设想就是说,我们有一个Servlet类,在接收到请求之后会找到对应得处理请求的方法的话,那就可以解决了
这样的话就是把处理请求的方法看作一个个类,然后建立对应关系
实现要求:
- 能识别出不同请求的具体名字java里
uri
- 处理请求的方法类一定要提前创建在内存里(如果new代表着你要在接收到请求,判断之后才把类创建出来。等待时间肯定很长)
java代码在计算机中经历的三个阶段
blog.csdnimg.cn/20200815172616217.png#pic_center)
反射的一个具体应用:
类的字节码加载进了虚拟机,然后将类的方法封装成一个个类,然后展示出来
在这里插入图片描述
反射的好处
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性
获取Class对象的方式
- Class.forName(“全类名”);将字节码文件加载进内存,返回Class对象
- 多用于配置文件,将类名定义在配置文件中,读取文件,返回Class对象
- 类名.class;通过类名的属性class获取
- 多用于参数的传递
- 对象.getClass();继承Object的getClass()方法
- 多用于对象的获取字节码的方式
//1. Class.forName(“全类名”)
Class cla = Class.forName("com.zhq.test.Person");
//2. 类名.class
Class cla1 = Person.class;
//3. 对象.getClass()
Person person = new Person();
Class cla2 = person.getClass();
System.out.println(cla);
System.out.println(cla1);
System.out.println(cla2);
//比较三个对象
System.out.println(cla == cla1);
System.out.println(cla == cla2);
从内存地址一样可以看出来,三种方式的获取Class类对象都是同一个,说明同一个字节码文件(*.class)在一次程序运行过程中,只会加载一次,不论是通过哪一种方式获取Class对象都是同一个
Class对象功能
获取功能:
-
获取成员变量
getFields()
获取所有public修饰的成员变量getField(String name)
获取所有的成员变量getDeclaredFields()
getDeclaredField(String name)
-
获取构造方法
getConstructors()
getConstructor(类<?>... parameterTypes)
getDeclaredConstructors()
getDeclaredField(String name)
-
获取成员方法
getMethods()
getMethod(String name, 类<?>... parameterTypes)
getDeclaredMethods()
getDeclaredMethod(String name, 类<?>... parameterTypes)
-
获取类名
-
getName()
获取类名 -
getPackageName()
获取包名
-
//一个Person类
public class Person {
private String name;
private int age;
public int id;
public Person(){};
public void eat(){
System.out.println("eat..".)
};
}
Field:成员变量
//获取Person的s对象
Class personClass = Person.class;
//获取public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field:fields) {
System.out.println(field);
}
//获取所有成员变量getDeclaredFields()
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField:declaredFields) {
System.out.println(declaredField);
}
这个对象的操作(作用):
- 设置值
set(Object obj, Object value)
- 获取值
get(Object obj)
- 忽略访问权限修饰符的安全检查
setAccessible(true)
操作public修饰的变量
//获取public成员变量id的值
Field id = personClass.getField("id");
Person p = new Person();
Object value = id.get(p);
System.out.println(value); //预计是0
//设置public成员变量id的值
id.set(p,123456);
System.out.println(p);
操作私有private变量(需要忽略访问权限修饰符的安全检查)
Field name = personClass.getDeclaredField("name");
//忽略访问权限修饰符的安全检查
name.setAccessible(true);//暴力反射,如果不加会报IllegalAccessException
Object value1 = name.get(p);
System.out.println(value1);
name.set(p,"张三");
System.out.println(value1);
Constructor:构造方法
创建对象:
newInstance(Object... initargs)
注意如果使用空参构造方法创建对象,操作可以简化:Class对象的newInstance
方法
//getConstructor(类<?>... parameterTypes)
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//创建对象
Object person = constructor.newInstance("张三", 23);
System.out.println(person);
Method:成员方法
执行方法:
invoke(Object obj, Object... args)
获取方法名:
get name()
//getMethod(String name, 类<?>... parameterTypes)
Method eat = personClass.getMethod("eat");
Person p = new Person();
//执行空参方法
eat.invoke(p);
Method eat_method = personClass.getMethod("eat", String.class);
//一参方法
eat_method.invoke(p,"苹果");
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method:methods) {
System.out.println(method);
}