文章目录
- 什么是反射
- 反射定义
- java创建对象的三个阶段
- 反射过程
- 反射第一步:获取类对象
- 获取类对象的三种方式
- 反射第二步:获取类信息
- 如何获取类信息?
- 1、获取成员变量:
- 2、获取方法:
- 3、获取构造器
- 反射第三步:使用反射信息
- 1、使用构造器 / 如何使用构造器 (构造器主要是用来创建对象的)
- 2、方法的使用 / 如何使用方法
- 3、变量的使用 / 如何使用变量 ----赋值、取值
——————————————————————————
什么是反射
- servlet是怎么运行的呢?
——> servlet里面没有main方法
——>servlet运行就用到了反射
private——私有的
public——公开的
protected——受保护的
String password——default默认为空的 - 如何给这些数据赋值?
2.1 创建一个对象进行赋值
——> 通过对象调用变量 或者 改变了的set()方法进行赋值
——>
private类型的可以创建方法
2.2 利用反射赋值
所谓的反射赋值其实就是通过获取类信息,然后创建对象,通过对象给获取到的类信息赋值
反射定义
反射:拥有获取类信息的能力
创建对象的流程:
1、自定义java文件—>demo.java—>javac命令编译成demo.class——>通过.java命令运行到JVM内存(加载到方法区,方法区存储的是类信息 (类对象) )
(简单理解为:从类到对象的过程)
2、main方法入栈——>main方法创建类student对象——>student对象在堆内存中开辟内存空间——>堆当中,对象内部有变量的空间,存有变量(name,age,password,sno,age)
java创建对象的三个阶段
- 磁盘阶段 - - - - - -在d盘或在c盘等磁盘当中
- 类对象阶段 - - - - - -加载到内存的阶段
- 运行阶段
(在堆内存那块内存区域的叫做对象,方法区当中是类对象)
为什么一个类可以创建多个对象???——>因为类对象时刻保存在方法区当中,所以才可以时刻创建出多个对象
反射过程
反射第一步:获取类对象
获取类对象的三种方式
如何获取类对象?
方式一:通过Class.forName(“全类名”)变量来获取类对象(全类名:包名+类名)------(对应磁盘阶段,磁盘阶段就是地址形式进行存储)
方式二:类名.class ------ 类本身已经构建成了类对象,加载到磁盘当中了,因此不需要写全类名,直接类名.class就能获取类对象(对应类对象阶段)
方式三: 对象名.getClass ------ 已经生成了对象,(回退)(对应运行阶段)
反射第二步:获取类信息
如何获取类信息?
1、获取成员变量:
想获取成员变量——>通过Field类/类对象提供了一些方法
—1—>类对象.getDeclaredFields(); -------获取所有的变量,由Field[]数组进行接收
Field[] fields = class1.getDeclaredFields();
—2—>类对象.getFields(); -------获取全部的public修饰的变量,由Field[]数组进行接收
Field[] fields1 = class1.getFields();
—3—>类对象.getDeclaredField(“参数”); -------获取指定的变量,参数为指定变量名,由Field变量进行接收
Field name = class1.getDeclaredField(“name”);
—4—>类对象.getField(“参数”); -------获取指定的public修饰的变量,参数为指定变量名,由Field变量进行接收
Field password= class1.getField(“password”);
总结:方法上有Declared能获取全部的,没有Declared只能获取public修饰的变量
当sno是protected类型的时候
Field sno = class1.getField(“sno”);//会报错
2、获取方法:
—1—>类对象.getDeclaredMethods() ---------获取全部的方法,由Method[]数组接收
Method[] methods = class1.getDeclaredMethods();
—2—>类对象.getMethods() ---------获取全部的public修饰的方法,由Method[]数组接收
Method[] methods = class1.getMethods();
—3—>类对象.getDeclaredtMethod(“方法名”,“该参数的反射类型 . 该方法的参数”) ---------获取指定的方法,所有类型都可以获取,由Method变量进行接收
( 方法没有参数的时候就不写后面的"参数的类型 . 该方法的参数" )
—4—>类对象.getMethod(“方法名”,“该参数的反射类型 . 该方法的参数”) ---------获取指定的public类型修饰的方法,由Method变量进行接收
3、获取构造器
—1—>类对象.getDeclaredConstructors() ---------获取全部的构造方法,由Constructor[]数组接收
Constructor[] Constructor = class1.getDeclaredConstructors();
—2—>类对象.getConstructors() ---------获取全部的public修饰的构造方法,由Constructor[]数组接收
Constructor[] Constructor = class1.getConstructors();
—3—>类对象.getDeclaredConstructor(该参数的反射类型) ---------获取指定的构造方法,由Constructor变量接收
Constructor Constructor = class1.getDeclaredConstructor();
—4—>类对象.getConstructor(该参数的反射类型) ---------获取指定的public类型的构造方法,由Constructor变量接收
Constructor Constructor = class1.getConstructor();
所有构造器的方法名是一样的
反射第三步:使用反射信息
1、使用构造器 / 如何使用构造器 (构造器主要是用来创建对象的)
通过调用newInstance()方法来创建对象(constructor.newInstance();)
Student student = (Student) constructor.newInstance();//利用构造器生成对象
如果想要使用私有类型的数据,必须使用暴力反射
——》constructor.setAccessible(true);
对于私有的数据,必须使用暴力反射才能使用,不是私有类型的数据,不需要使用暴力反射
Class<?> clazz = Class.forName("fanshe.com.Student");
Constructor constructor = clazz.getDeclaredConstructor();
//如果想要使用私有类型的数据,必须使用暴力反射
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance();//利用构造器生成对象
System.out.println(student.sex);//这样才能使用
注:(总结)
构造器本质:创建对象
1、获取指定的构造器:如果是public修饰的,用getConstructor(“参数的反射类型”),如果是非public修饰的用getDeclaredConstructor(“该参数的反射类型”)
2、通过调用newInstance()方法来创建对象------newInstance(参数的值):如果是private类型修饰的构造器,需要暴力反射。
【获取到的指定构造器名.setAccessible(true);】
3、想使用public 和 protected 等非私有类型修饰的数据 ------ :不需要使用暴力反射
2、方法的使用 / 如何使用方法
调用invoke(对象,该方法的参数)方法 用来执行指定的方法
Class<?> clazz = Class.forName("fanshe.com.Student");
Method method = clazz.getMethod("eat",String.class);
//为什么要创建对象??——》获取类信息是处在类对象阶段,方法、变量在第三阶段
//因为获取的类信息来源于第二阶段(对象阶段),但是要使用方法需要进入到第三阶段,创建对象,给方法内存空间才能进行调用
Student student = new Student("张三");
method.invoke(student,"水果");
———————————————以上是不使用反射的时候,使用反射是下面这样———————————————————————
Class<?> clazz = Class.forName("fanshe.com.Student");
Constructor construcor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance();//调用newInstance()来创建当前对象
method.invoke(student,"水果");
--------
Student.java当中有:
private Student(){
}
注:
1、获取指定所有的方法
2、创建对象 -------为什么要创建对象??——》因为获取的类信息来源于第二阶段(对象阶段),但是要使用方法需要进入到第三阶段,创建对象,给方法内存空间才能进行调用,所以需要提前创建出对象
3、如果是private类型修饰,需要暴力反射 ,如果是其他类型不需要暴力反射
4、调用invoke方法---------获取的方法类信息.invoke(对象,参数的值…);
3、变量的使用 / 如何使用变量 ----赋值、取值
Class<?> clazz = Class.forName("fanshe.com.Student");
//获取类信息
Field field = clazz.getDeclaredField();
field.setAccessible(true);
//赋值 set方法
field.set(student,"张三");
//取值 get方法
field.get(student);
System.out.println(field.get(student));//输出:张三
注:(总结)
1、获取指定的变量------如果是public修饰的变量getField(“方法名”) 、如果是非public修饰的用 类对象.getDeclareField(“name”)
2、创建对象 ------为什么要创建对象??—>因为获取的类信息来源于第二阶段(对象阶段),但是要使用变量需要进入第三阶段,创建对象,给变量内存空间才能进行调用
3、如果是privated修饰的变量需要暴力反射 获取的变量类信息.setAccessible(true)
4、赋值:变量信息.set(对象,值)
5、取值:变量信息.get(对象)