反射

您所在的位置:网站首页 java反射获取对象属性和顺序 反射

反射

2024-07-12 10:33| 来源: 网络整理| 查看: 265

反射 一、反射的概述 1、反射概念

反射:反射是一种机制,利用该机制在程序运行过程中对类进行解剖并操作类中的所有成员(成员变量、成员方法、构造方法)

2、 反射过程 反射过程描述: 首先会有一个java文件,然后会编译成.class文件,字节码文件(会里面包含了当前这个类里面所有数据信息)会加载到内存,JVM负责管理,为了方便管理,它会将每一个加载进来的class文件生成一个对应的Class对象,这个class对象它就代表对应的类(java文件),那么我们可以通过这个类对应的class对象获得这个类中的数据信息(成员变量、成员方法、构造方法) 在这里插入图片描述

结论:我们使用反射,其实就是获得某个类的Class对象,然后通过这个Class对象对这个类中的成员数据进行处理(调用执行)!

3、反射前提

我们必须得到这类的字节码文件(.class文件) ====>>> Class对象

Java类与Class对象的对应关系: 一个类 =======>>> 一个Class对象 类中的一个成员变量 ======>>>> 一个Field对象(在程序运行阶段为类中的成员变量赋值或者获取值) 类中的一个成员方法 ======>>>> 一个Method对象(在程序运行阶段执行类中的成员方法) 类中的一个构造方法 ======>>>> 一个Constructor对象(在程序运行阶段创建当前类的一个实例对象) 二、Class对象 1.1 获得Class的对象(三种方式) 最常用的一种和第三种方式一:通过Class类的静态方法 // 参数:某个类的全限定类名(包含包名和类名) static Class forName(String className) // 返回与给定字符串名称的类或接口相关联的Class对象。 Class clazz = Class.forName("com.itheima.demo01_反射.Student"); // 给定类的全限定类名书写错误,会导致异常!ClassNotFoundException 方式二:通过类的对象的getClass()方法 // 先获得到某个类的对象 Student student = new Student(); // 通过对象调用方法获得Class对象! Class clazz1 =student.getClass(); // getClass()方法是从Object继承过来的 方式三:通过类名的静态属性class // 通过类名.class获得Class对象! Class clazz = Student.class; 1.2 Class对象的常用功能 * String getSimpleName(); // 获得类名字符串:类名 * String getName(); // 获得类全名:包名+类名 * T newInstance() ; // 创建Class对象关联类的对象(公有构造方法)

代码展示

public static void main(String[] args) throws Exception{ // 获得Student类对应的Class对象 Class clazz = Class.forName("com.itheima.demo01_反射.Student"); System.out.println(clazz.getSimpleName()); // Student System.out.println(clazz.getName()); // com.itheima.demo01_反射.Student Object obj = clazz.newInstance(); // com.itheima.demo01_反射.Student@1647C } 三、 通过Class对象操作构造方法 1.1 获得Constructor对象(四种方式) Constructor[] getConstructors() // 通过Class对象获得类中所有的公有的构造方法对象 (数组)Constructor[] getDeclaredConstructors() // 通过Class对象获得类中所有的构造方法对象(公有私有,全都要) (数组)Constructor getConstructor(Class… parameterTypes) // 通过Class对象获得类中指定公有的构造方法对象! 【★★★★★】Constructor getDeclaredConstructor(Class… parameterTypes) // 通过Class对象获得类中指定的构造方法!(公有私有,全都要)

代码展示

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { // 获得Student类对应的Class对象 Class clazz = Class.forName("com.itheima.demo01_反射.Student"); /* 通过Class对象获得Student类中构造方法对应的Constructor对象!*/ // 获得类中所有的公共的构造方法对应的**对象数组** Constructor[] constructors = clazz.getConstructors(); // 获得类中所有的构造方法对应的**对象数组**(包括私有的!) Constructor[] dc = clazz.getDeclaredConstructors(); /* 获得类中指定构造方法对应的对象*/ //获取public修饰的空参构造对象 Constructor c1 = clazz.getConstructor(); //获取public修饰的带参构造对象 Constructor c2 = clazz.getConstructor(String.class, int.class); //不仅可以获取public修饰的还可以获取private修饰的空参构造对象 Constructor c3 = clazz.getDeclaredConstructor(); //不仅可以获取public修饰的还可以获取private修饰的带参构造对象 Constructor c4 = clazz.getDeclaredConstructor(String.class, int.class); } 1.2 通过构造方法对象创建类的实例对象 T newInstance(Object… initargs) ----------使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。 public static void main(String[] args) throws Exception{ // 获得Student类对应的Class对象 Class clazz = Class.forName("com.itheima.demo01_反射.Student"); // 获得Student类中指定的构造方法对象! Constructor constructor = clazz.getConstructor(); // 根据构造方法对象创建Student类的实例对象! Object o = constructor.newInstance(); System.out.println(o); // com.itheima.demo01_反射.Student@14ae5a5 Student s = (Student) o; }

注意:一旦类中的构造方法使用private修饰,那么通过构造方法对象创建了的实例对象就要发生变化!

public static void main(String[] args) throws Exception{ // 获得Student类对应的Class对象 Class clazz = Class.forName("com.itheima.demo01_反射.Student"); // 获得Student类中指定的构造方法对象! Constructor constructor = clazz.getDeclaredConstructor(); // 有变动! // 暴力反射! constructor.setAccessible(true); // 有变动! // 根据构造方法对象创建Student类的实例对象! Object o = constructor.newInstance(); System.out.println(o); // com.itheima.demo01_反射.Student@14ae5a5 Student s = (Student) o; } 四、 通过Class对象操作成员方法对象 1.1 获得成员方法的Method对象(四种方式)

Method getMethod(String name, Class… parameterTypes) // 返回指定公有的方法对象! 【★★★★★】

Method[] getMethods() // 返回所有公有的方法对象构成的数组,包括由类或接口声明的对象以及从超类和超级接口继承的类。

Method getDeclaredMethod(String name, Class… parameterTypes)// 返回指定的方法对象!(共有的、私有的全部)

Method[] getDeclaredMethods() // 返回所有的方法对象构成的数组,包括public,protected,default(package)访问和私有方法,但不包括继承方法。

代码展示

public static void main(String[] args) throws Exception{ // 获得Student类对应的Class对象 Class clazz = Class.forName("com.itheima.demo01_反射.Student"); // 获得Student类以及父类(接口)中所有的公有成员方法 Method[] methods1 = clazz.getMethods(); for (Method method : methods1) { System.out.println(method); } // 获得Student类中所有的成员方法(包含私有)(不包含继承的) Method[] methods2 = clazz.getDeclaredMethods(); for (Method method : methods2) { System.out.println(method); } // 获得指定方法(公有无参) Method show1 = clazz.getMethod("show1"); // 获得指定方法(私有无参) Method show2 = clazz.getDeclaredMethod("show2"); // 获得指定方法(公有带参数) Method method1 = clazz.getMethod("method1", String.class); } 1.2 通过Method对象执行指定方法 /* 参数obj:当前Method对象所属的类的对象!【实际的对象值!】 参数args:为方法对象的形参赋值(若方法对象对应的方法定义没有参数,这里可以空着不写) 返回值Object:执行完当前方法的返回结果! */ Object invoke(Object obj, Object... args) // 在具有指定参数的指定对象上调用此 方法对象表示的基础方法。 【★★★★★】

代码展示

public static void main(String[] args) throws Exception{ // 获得Student类对应的Class对象 Class clazz = Class.forName("com.itheima.demo01_反射.Student"); // 创建类的对象 Object obj = clazz.getConstructor().newInstance(); // 获得指定方法(公有无参) Method show1 = clazz.getMethod("show1"); // 获得指定方法(公有带参数) Method method1 = clazz.getMethod("method1", String.class); // 获得成员方法对象,期目的是为了执行这个成员方法 Object result = show1.invoke(obj);// 参数1:当前方法所属对象! 参数2:show1方法的参数值(若定义show1方法没有参数,这里就不写内容) // 执行带有参数的公有成员方法 Object o = method1.invoke(obj, "666");// 参数1:当前方法所属对象! 参数2:method1方法的参数值 System.out.println(o); } 五、 通过Class对象操作成员变量 1.1 获得成员变量的Field对象(四种方式) Field[] getFields();//获得公有成员变量对应的Field对象(继承的也显示)Field .getField(“name”);// 获得指定公有成员变量Field[] getDeclaredFields(); //获得所有的成员变量对应的Field对象(公有私有均可)(继承的不显示)Field getDeclaredField(“age”); //获得指定成员变量(公有私有均可) 代码展示 public static void main(String[] args) throws Exception{ // 获得Student类对应的Class对象 Class clazz = Student.class; // 获得类的实例 //Object obj = clazz.newInstance(); Student s = (Student) clazz.newInstance(); //一、获得公有成员变量对应的Field对象(继承的也显示) Field[] fields = clazz.getFields(); //二、 获得指定公有成员变量 Field name = clazz.getField("name"); // 三、 获得所有的成员变量对应的Field对象(公有私有均可)(继承的不显示) Field[] declaredFields = clazz.getDeclaredFields(); // 四、 获得指定成员变量(公有私有均可) Field age = clazz.getDeclaredField("age"); } 1.2 通过Field对象获取成员变量的值或者设置值 public static void main(String[] args) throws Exception{ // 获得Student类对应的Class对象 Class clazz = Student.class; // 获得类的实例 //Object obj = clazz.newInstance(); Student s = (Student) clazz.newInstance(); /* 操作公有的成员变量*/ // 获得指定公有成员变量 Field name = clazz.getField("name"); // 为公有的成员变量设置值 name.set(s,"jack"); // 获得指定公有成员变量的值 System.out.println(name.get(s)); // jack System.out.println(s.getName()); // jack /*操作私有的成员变量*/ // 获得指定成员变量(公有私有均可) Field age = clazz.getDeclaredField("age"); // 暴力访问 age.setAccessible(true); // 获取值 System.out.println(age.get(s)); // 0 // 设置值 age.set(s,38); System.out.println(age.get(s)); // 38 } 反射总结

一、创建Class对象的三种方式及常用方法 1、类名.class 2、Class.fotName(“全类名”) 3、类的对象名.getClass getSimple()–得到类名、个体getName()–得到全类名、newInstance()–创建类的对象

二、通过Class对象操作构造方法(四种)及创建实例对象的方法 1、getConstructors() 2、getDeclaredConstructors() 3、getConstructor(Class… parameterTypes) 4、getDeclaredConstructor(Class… parameterTypes) newInstance()–创建空参实例对象 newInstance(Object… initargs)–创建带参实例对象

三、通过Class对象操作方法(四种)及调用方法 1、getMethods() 2、getDeclaredMethods() 3、getMethod(String name ,Class… parameterTypes) 4、getDeclaredMethod(String name ,Class… parameterTypes) 方法对象.invoke(实例对象,参数)

四、通过Class对象操作成员变量(四种)及常用方法 1、getFields() 2、getDeclaredFields() 3、getField(String name ) 4、getDeclaredField(String name ) 属性对象.get(实例对象) 属性对象.set(实例对象,实参)

五、反射可以抹除泛型 代码展示

ArrayList list = new ArrayList(); list.add("nihao"); list.add("shabi"); //list.add(111); 受泛型限制,编译期报错 Class clazz = list.getClass(); Method add = clazz.getMethod("add", Object.class); add.invoke(list,123); add.invoke(list,11.22); add.invoke(list,'a'); System.out.println(list);//[nihao, shabi, 123, 11.22, a]

原因: 泛型在编译期起作, 通过反射 绕过了编译器,在运行期执行时添加数据

六、当访问private修饰的成员是要使用setAccessible(true);//强制反射



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3