B站(UP主:黎曼的猜想 题目:Java基础+进阶)反射观看顺序:5、10、11、6、7、8、9
参考:https://blog.csdn.net/weixin_43691058/article/details/98783120
Java代码在计算机中经历的三个阶段:
1.源代码阶段(.java、.class文件在硬盘)
2.Class类对象阶段
通过类加载器将字节码文件加载到内存,一个类文件对应的是一个类对象
public class Class{
Field[] fields;//将成员变量封装成对象
Constructor[] constructors;//将构造函数封装成对象
Method[] methods;将成员方法封装成对象
Annotation[] annotations;将注解封装成对象
//获取成员变量
Field[] getFields()
Field getFields(String name)
Field[] getDeclaredFields()
Field getDeclaredFields(String name)
//获取构造方法
Constructor<?>[] getConstructors()
Constructor<T> getConstructor(类<?>……parameterTypes)//可变参数
Constructor<T> getDeclaredConstructor(类<?>……parameterTypes)
Constructor<?>[] getDeclaredConstructors()
//获取成员方法
Method[] getMethods()
Method getMethods(String name,类<?>……parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethods(String name,类<?>……parameterTypes)
//获取类名
String getName()
}
eg: String这个类的字节文件通过类加载器编程Class对象,把String这个类的成员变量、成员函数等封装成对象。
3.运行阶段(new 对象)String str = "123";
反射:将类的各个部分组成部分封为其他对象
要是想操作这些“其他对象”,重点是找到Class类对象。
获取Class类对象的方法:
1:当字节码文件还没有进内存:Class.forName("全类名");//将字节码文件加载到内存,返回Class对象
2:字节码文件已经在内存,但是没有new 对象();//类名.class:通过类名获取
Class.forName():使用这个时,会将字节文件加载到内存。所以可使用类名.class;
3:已经new 对象();//对象.getClass();,getClass这个方法在Object这个类中定义的。
注意:
同一个字节码文件(*.class)在一次程序运行过程中,只会加载一次,不论通过哪一种方式获取Class对象都是同一个。
找到Class类对象,可以使用它的方法,主要是是获取功能(获取“其他对象”)
//获取成员变量
Field[] getFields()//获取public成员变量
Field getFields(String name)//获取public指定成员变量
//拿到成员变量Field field = getFields("");可以对成员变量进行设置和获取值
Object value = field.get(对象);//获取对象的叫name的成员变量的value值。
field.set(对象,"value值");//对对象叫name的成员变量进行赋值。
Field[] getDeclaredFields()//获取所有的成员变量,不考虑修饰符
Field getDeclaredFields(String name)
//拿到成员变量Field field = getDeclaredFields("");可以对成员变量进行设置和获取值(对private也可以赋值,反射面前没有私有还是公有)
field.setAccessible(true);//忽略访问权限修饰符的安全检查(暴力反射)
Object value = field.get(对象);//获取对象的叫name的成员变量的value值。
field.set(对象,"value值");//对对象叫name的成员变量进行赋值。
//获取构造方法
Constructor<T> getConstructor(类<?>……parameterTypes)//构造函数主要是关注参数列表
eg:
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class,int.class);
System.out.println(constructor);
问题:我们获得constructor这个对象能干什么?换言之,我们得到一个类的构造函数要干什么?
回答:
//创建对象
Object person = constructor.newInstance("张三",23);
System.out.println(person);
//创建对象
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor();//空参数
Object person1 = constructor.newInstance();
System.out.println(person1);
如果使用空参数进行创建对象时,操作是可以进行简化的
Class personClass = Person.class;
Object person2 = personClass.newInstance();
System.out.println(person2);
//获取成员方法
//成员函数关注方法名,参数列表,返回值
Method getMethods(String name,类<?>……parameterTypes)
//获取指定名称的方法名
Class personClass = Person.class;
Method method = personClass.getMethods("方法名称","参数列表");//空参数
//得到method对象一般是想执行这个方法
Object invoke(Object object,Object……args);
//获取方法名称
String name = method.getName();
eg:
Person person = new Person();
method.invoke(person);//method没有参数,就不用传了。
//有参数
Class personClass = Person.class;
Method method1 = personClass.getMethods("eat",String.class);
method.invoke(person,method1);//method没有参数,就不用传了
//method方法就可以执行了
//获取所有的public方法
Method[] methods = personClass.getMethods();
for(Method method:methods){
System.out.println(method);
System.out.println(method.getName());//获取方法名称
}
当打印类对象的方法成员Field中包含自己的方法还有Object的方法。
//获取类名
Class personClass = Person.class;
String name = personClass.getName();
System.out.println(name);//输出的是全类名
反射的好处
1:可以在程序运行过程中,操作着希望
2:可以解耦,可以调高程序的可扩展性。