一.反射的原理图
二.获取class对象<字节码文件对象>的方式
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. 类名.class:通过类名的属性class获取
* 多用于参数的传递
3. 对象.getClass():getClass()方法在Object类中定义着。
* 多用于对象的获取字节码的方式* 结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
三.class对象的功能
获取构造方法
获取成员方法
获取成员变量
三.(1)获取构造方法
获取构造方法们:
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(类<?>... parameterTypes)* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()//0.获取Person的Class对象 Class<Person> personClass = Person.class; //1.获取带参的构造方法 Constructor<Person> constructor = personClass.getConstructor(String.class, int.class); Person person = constructor.newInstance("张三", 23); System.out.println(person); System.out.println("================================="); //2.获取不带参的构造方法可以使用更简便的方法 // 使用字节码文件对象,直接获取构造方法 Person person1 = personClass.newInstance(); System.out.println(person1);
注意事项:
1.不带Declared的方法,如:
* Constructor<?>[] getConstructors() * Constructor<T> getConstructor(类<?>... parameterTypes)这两个方法只能获取被public修饰的构造方法.
2.带Declared的方法,如
* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors()这两个方法是可以获取被任何修饰符修饰的构造方法的
3.如果用构造方法来声明对象的话;
带参的构造方法,要先用字节码文件对象获取构造方法,其中参数中要带上类型的字节码文件对象
然后用获取到的构造方法来声明类的对象
不带参的构造方法:可以直接用字节码文件对象,调用newInstance()来获取类的对象
三.(2) 获取成员方法
获取成员方法们:
* Method[] getMethods()
* Method getMethod(String name, 类<?>... parameterTypes)* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name, 类<?>... parameterTypes)//0.获取Person的字节码文件对象 Class<Person> personClass = Person.class; //获取指定名称的不带参的方法 Method eat_method = personClass.getMethod("eat"); eat_method.invoke(new Person()); //传入类的对象 //此方式是直接声明Person类的对象 eat_method.invoke(personClass.newInstance()); //此方式是通过字节码文件对象来创建Person类的对象 //获取指定名称的带参的方法 Method eat_method2 = personClass.getMethod("eat", String.class); eat_method2.invoke(new Person(),"饭"); eat_method2.invoke(personClass.newInstance(),"香蕉"); System.out.println("================================================="); Method[] methods = personClass.getMethods(); //会把Object中的方法都一并获取了 for(Method method : methods){ System.out.println(method); //获取方法名, 不是全类名来的 System.out.println(method.getName()); } //如果要使用不是被public修饰的方法的话 //还是要调用setAccessible(true)方法来实现 //获取类名(全类名) String className = personClass.getName(); System.out.println(className);
注意事项:
1.不带Declared的方法,如:
* Method[] getMethods() * Method getMethod(String name, 类<?>... parameterTypes)这两个方法只能获取被public修饰的构造方法.
2.带Declared的方法,如
* Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 类<?>... parameterTypes)这两个方法是可以获取被任何修饰符修饰的成员方法的
3.调用获取的方法是使用 invoke方法的,方法中一定要传入类的对象
获取类的对象有两种方法:
(1) 用实体类直接new出来
(2) 用字节码文件对象,获取构造方法,然后通过调用newInstance()来获取类的对象
对于为啥在调用方法的时候,要传入类的对象的个人看法:
字节码文件中的methods数组中包含了类中所有的方法,在我们通过字节码文件对象获取了某一个方法之后,我们想要调用此方法,但是尴尬的是,我们并不知道这个方法是属于哪一个对象,不知道是p1对象的 还是p2对象的 抑或是 p3对象的,所以我们在调用方法的时候,必须传入实体类对象作为参数
4.如果调用获取的方法中,是带参数的,那么调用方法的时候,参数是加在实体类对象之后的
三.(3)获取成员变量
获取成员变量们
* Field[] getFields()
* Field getField(String name)* Field[] getDeclaredFields()
* Field getDeclaredField(String name)//0.获取字节码文件对象 Class<Person> personClass = Person.class; //1.Field[] getFields()获取所有public修饰的成员变量 Field[] fields = personClass.getFields(); for(Field field : fields){ System.out.println(field); } System.out.println("====================================="); //2.Field getField(String name) Field a = personClass.getField("a"); //只能获取被public修饰的属性 // 获取成员变量a的值 Person person = new Person(); Object value = a.get(person); System.out.println(value); //设置a的值 a.set(person,"张三"); System.out.println(person); System.out.println("======================================"); //Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符 Field[] declaredFields = personClass.getDeclaredFields(); for(Field declaredField : declaredFields){ System.out.println(declaredField); } //Field getDeclaredField(String name) 获取指定的成员变量,并且不考虑修饰符 Field d = personClass.getDeclaredField("d"); //忽略访问权限修饰福的安全检查 d.setAccessible(true); //暴力反射 Object value2 = d.get(person); System.out.println(value2);
注意事项:
1.不带Declared的方法,如:
Field[] getFields() * Field getField(String name)这两个方法只能获取被public修饰的成员变量.
2.带Declared的方法,如
* Field[] getDeclaredFields() * Field getDeclaredField(Strin g name)这两个方法是可以获取被任何修饰符修饰的成员变量的
3.对于成员变量来说,操作成员变量只有两种可能:
(1)获取成员变量的值:
使用get方法,其中get方法中,要传入实体类的对象,因为要知道获取哪一个对象中的成员方法
(2)设置成员变量的值
使用set方法,其中,第一个参数一定是传入实体类的对象,因为要知道给哪一个成员变量赋值,后面的参数是所赋的值
4.如果要获取不是被public所修饰的成员变量的值或者给不是被public所修饰的成员变量赋值',一定要忽略访问权限修饰符的安全检查
d.setAccessible(true); //暴力反射
此处,d为获取的成员变量,要先暴力反射,才能做后续的操作.