初识反射

    技术2022-07-11  96

    初识反射(java.lang.reflect)

    什么是反射?

    class是一切反射的根源,JAVA反射机制是在运行状态中,对于任和一个类,通过反射都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

    反射的原理

    在程序运行的时候获取到想要创造实例的类的信息,使用Class类来创建一个对应的实例。避免了使用new关键字,达到在程序运行时动态创建实例的效果。

    反射提供的以下几个类,可在类中查询具体的方法

    java.lang.Class;

    java.lang.reflect.Constructor;

    java.lang.reflect.Field;

    java.lang.reflect.Method;

    java.lang.reflect.Modifier;

    如何实现反射

    1、获得类的信息(获得到的是类的全路径信息)

    获得类的信息有三种方式:

    1.使用class类的forName()方法获取类的信息(比较推荐) 2.使用对象实例的getclass()方法获得类的信息 3.使用类名.class获得类的信息 Demo:

    /*三种获得反射对象的方法*/ //第一种 Class.forName("全限定类名") Class class1 = class1 = Class.forName("com.test.entity.One"); //第二种类名.class Class class2 = One.class; //第三种对象.getclass One one = new One(); Class class3 = one.getClass(); System.out.println(class1); System.out.println(class2); System.out.println(class3); //运行结果 class com.test.entity.One class com.test.entity.One class com.test.entity.One

    当程序运行,第一次加载类时,先将硬盘上.class文件加载内存中,这时类加载器和JVM会根据.class文件生成.class对象,这个对象叫反射对象.一个类只有一 个反射对象.

    //类的反射对象只有一个,因为当前类的class字节码文件只有一个 System.out.println(class1 == class2); System.out.println(class2 == class3); System.out.println(class1 == class3); //运行结果 true true true

    2、使用反射对象获得实例对象

    //使用反射对现象获得类的实例对象 //无参构造创建实例对象 One one1 = (One) class1.newInstance(); //有参构造创建实例对象 Constructor constructor = class1.getConstructor(String.class,int.class); One one2 = (One) constructor.newInstance("张三",20); System.out.println(one2); //有参构造方法创建实体类运行结果 One{name='张三', age=20}

    3、使用反射对象获得类的属性(Field)

    //使用反射对象获得类的私有属性 Field field2 = class1.getDeclaredField("name"); //给属性设置允许访问私有 field2.setAccessible(true); //给属性设置值,第一个参数是要给哪个实例对象设置当前属性的值 field2.set(one1,"张无忌"); //查看设置结果 System.out.println(one1); //运行结果 One{name='张无忌', age=0}

    也可以一次性获得所有属性的数组

    //获得所有私有属性 Field[] field = class1.getDeclaredFields(); for (Field field1 : field) { System.out.println("属性名称"+field1.getName()+"属性类型"+field1.getType()); } //运行输出结果 属性名称name属性类型class java.lang.String 属性名称age属性类型int 属性名称father属性类型class java.lang.String

    获得公有属性

    //获得公有属性 Field field3 = class1.getField("father"); field3.set(one,"张三丰"); //查看设置结果 System.out.println(field3.get(one)); //运行输出结果 张三丰

    4、使用反射对象获得类的方法(Method)

    /*使用反射对象获得方法*/ //获得私有方法 //第一个参数为方法名,第二个参数开始是参数类型,如果有多个参数,按顺序写入 Method method = class1.getDeclaredMethod("show1"); method.setAccessible(true);//设置允许访问私有 //参数含义是调用哪个实例对象的当前方法 method.invoke(one2);

    调用有参方法

    //获得私有有参方法 Method method1 = class1.getDeclaredMethod("show2",String.class); method1.setAccessible(true); //调用方法,将参数填入,如果多个参数则按顺序填入 method1.invoke(one2,"帅哥");

    获得公有方法

    //获得公有方法 无需设置访问权限 Method method2 = class1.getMethod("show3"); method2.invoke(one);

    反射的用法举例

    在这个demo中我有两个类,两个类中各有一个方法 此时如果项目中我是用的是XXX这个类的方法,但是由于业务需求需要更换成XXXX中的方法,如果使用常规方法,此时你可能需要修改代码,然后重新编译运行,才能达到效果

    package com.test.entity; public class XXX { public void X(){ System.out.println("这是XXX的方法"); } } package com.test.entity; public class XXXX { public void X(){ System.out.println("这是XXXX的方法"); } } public static void main(String[] args){ // XXX xxx = new XXX; // xxx.X(); //重新修改代码 XXXX xxxx = new XXXX(); xxxx.X(); }

    但是如果使用反射,则会方便快捷许多

    首先准备一个properties配置文件,里面写上两个属性,一个是类名,一个是方法名

    classname=com.test.entity.XXXX methodname=X

    然后在测试类中这样写

    package com.test.test; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; public class Test3 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException { File configfile = new File("D:\\IDEACode\\yanjiang\\src\\com\\test\\config\\configfile.properties"); Properties properties = new Properties(); //加载配置文件 properties.load(new FileInputStream(configfile)); //读取配置文件信息 String classname = properties.getProperty("classname"); String methodname = properties.getProperty("methodname"); //获得反射对象 Class clazz = Class.forName(classname); //使用反射对象获得方法 Method method = clazz.getDeclaredMethod(methodname); Constructor constructor = clazz.getConstructor(); Object obj = constructor.newInstance(); method.invoke(obj); } } //运行结果 这是XXXX的方法

    此时我们如果要更换类和方法只需要在配置文件中更改即可,无需重新new对象

    其他常用方法

    方法含义getDeclaredMethods()/getMethods获取本类所有的方法(包括私有方法)/获取所有的方法(包括父类的方法)getReturnType()获得方法的返回值类型getParameterTypes()获得方法的传入参数类型getDeclaredMethod(“方法名”,参数类型.class,……)获得特定的方法构造方法关键字getDeclaredConstructors()获取所有的构造方法getDeclaredConstructor(参数类型.class,……)获取特定的构造方法父类和父接口getSuperclass()获取当前类的父类getInterfaces()获取其类实现的接口

    PS:反射使用不当会造成很高的成本!

    Processed: 0.012, SQL: 9