Java-反射

参考:https://mp.weixin.qq.com/s/UYqPCmo2vpAibJPh6cupLw

1.定义

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

Java 的反射机制的实现要借助于4个类:class,Constructor,Field,Method,我们依次来说一下

2.获取Class对象的三种方式(Class 是反射的入口)

这个三个方式,我之前有提到过,我们再来重温一下:

  • 通过Class类的forName(String clazzName)静态方法,参数为类的完全限定名,即包含包名的完整路径。
  • 通过类的class属性
  • 通过调用某个对象的getClass()方法

相关代码如下:
思路首先创建Student实体类,然后用这三种方式获取。
创建实体类(我这里直接把最终的实体类呈现)

public class StudentBean {

    public  String name ;
    public String gender;
    //注意age属性是私有的,其余是公共的
    private String age;

    public StudentBean() {
    }

    public StudentBean(String name, String gender, String age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gendpublic class StudentBean extends DataSupport {

    public  String name ;
    public String gender;
    //注意age属性是私有的,其余是公共的
    private int age;

    public StudentBean(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    private StudentBean(String name, String gender) {
        this.name = name;
        this.gender = gender;

    }

    public StudentBean() {

    }



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 学生信息打印公共方法
     * @return
     */
    public String getStudentMesage(){
        return  "该学生信息如下:{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age='" + age + '\'' +
                '}';
    }


    /**
     * 公共的带形参的方法
     * @return
     */
    public String getStudentName(String name){
        return this.name;
    }


    /**
     * 私有的带形参的方法
     * @return
     */
    private int getStudentAge(int age){
        return this.age;
    }

    /**
     * 公共的带私有形参的方法
     * @return
     */
    public int getPrivateAge(int age){
        return age;
    }

    /**
     * 反射运行XML文件调用的测试方法
     */

    public void reflectXmlMethod(){
        System.out.println("反射运行XML文件调用的方法打印成功");
    }
}

获取Class对象方式

Class  mStudentBean;
        //第一种方式,通过Class.forName()
        try {
            mStudentBean=Class.forName("com.xzt.demo.bean.StudentBean");
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //第二种方式,通过类.class
        mStudentBean=StudentBean.class;
       
        //第三种方式,通过对象的getClass()方法
        mStudentBean=new StudentBean().getClass();

3.反射查看信息

我们开始说到反射的定义:对于任意一个类,都能够知道这个类中的所有属性和方法。
那我们继续尝试利用上面获取的Student对象获取它的属性和方法,但再次之前,我们需要了解Field.
成员变量-Field

java.lang.reflect.Field 为我们提供了获取当前对象的成员变量的类型,和重新设值 的方法。

成员变量Field的类型和我们常见的变量类型一样:

分为两种类型:基本类型和引用类型:
基本类型( 8 种)
整数:byte, short, int, long
浮点数:float, double
字符:char
布尔值:boolean
引用类型
所有的引用类型都继承自 java.lang.Object
类,枚举,数组,接口都是引用类型
java.io.Serializable 接口,基本类型的包装类(比如 java.lang.Double)也是引用>>类型

获取Field变量类型的方法

java.lang.reflect.Field 提供了两个方法获去变量的类型:
Field.getType():返回这个变量的类型
Field.getGenericType():如果当前属性有签名属性类型就返回,否则就返回
Field.getType()

3.1查看类属性

直接上代码:

  /  /**
     * 获取类属性
     */
    public void getClassAttribute(Class aClass){
        //获取class对象的所有属性
        Field[] allFields = aClass.getDeclaredFields();
        //获取class对象的public属性
        Field[] publicFields = aClass.getFields();
        try {
            //获取class指定属性
            Field ageField = aClass.getDeclaredField("age");
            //获取class指定的public属性
            Field nameField = aClass.getField("name");
            Field genderField = aClass.getField("gender");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            Log.e(TAG, "getClassAttribute: "+e.getMessage() );
        }
   }

我们来总结一下这几个方法:

  • Class.getDeclaredFields(),此方法获取的是类的所有属性数组,包括Private,Public等,我们运行的结果如下:


    Java-反射_第1张图片
    image.png
  • Class.getFields(),此方法只能获取Public的属性数组,我们运行结果如下:


    Java-反射_第2张图片
    image.png
  • Class.getDeclaredField("属性名"),获取指定属性,包括Private和Public等,如图:
    Java-反射_第3张图片
    image.png
  • Class.getField("属性名");词方法获取公共的属性,不包括Private属性。如下:


    Java-反射_第4张图片

那如果我们用getField()方法获取Private属性会怎么样呢?


Java-反射_第5张图片
image.png
3.2查看类方法

成员方法-Method

Method代表我们获取到一个类的所有方法的属性,在method类里头,我们可以获取到所有关于这个类里头方法的所有信息,包括方法名,方法的修饰符和方法的入参和返回参数等等的详细信息。

直接上代码,注释都清楚:

 /**
     * 获取类方法
     */
   public void getClassMethod(Class mClass){
       //获取class类所有声明方法(Private,Public),构造方法除外
       Method[] methods = mClass.getDeclaredMethods();
       //获取class对象的所有public方法,包括父类的方法
       Method[] allMethods = mClass.getMethods();
       try {
           //返回Class类中带形参的public方法,参数为方法名和参数类型
           Method method = mClass.getMethod("getStudentName", String.class);
           //返回Class类中带形参的方法,参数为方法名和参数类型
           Method declaredMethod2= mClass.getDeclaredMethod("getStudentAge", int.class);
       } catch (NoSuchMethodException e) {
           e.printStackTrace();
       }
   }

当然我只是举例了常用的方法,其他方法大家自行百度。

3.3 类的构造方法

类的构造器-Constructor

Constructor代表某个类的构造方法。

相关代码,都有注释就不过多解释了。

    /**
     * 获取类构造方法
     * @param mClass
     */
   public void getClassConstructMehtod(Class mClass){
       //获取class对象的所有声明构造函数(Private,Public)
       Constructor[] allConstructors = mClass.getDeclaredConstructors();
       //获取class对象public构造函数
       Constructor[] publicConstructors = mClass.getConstructors();
       try {
           //获取指定声明构造函数,参数为构造函数的参数类型(Private,Public)
           Constructor constructor = mClass.getDeclaredConstructor(String.class,String.class);
           //获取指定声明的public构造函数
           Constructor publicConstructor = mClass.getConstructor(String.class,String.class,int.class);
       } catch (NoSuchMethodException e) {
           e.printStackTrace();
       }
   }
3.4 获取类的其他信息的相关方法

    /**
     * 获取类的其他信息
     * @param mClass
     */
    public   void  getClassOtherMessage(Class mClass){
        ////判断是否是基础类型
        boolean isPrimitive = mClass.isPrimitive();
        //判断是否是集合类
        boolean isArray = mClass.isArray();
        //判断是否是注解类
        boolean isAnnotation = mClass.isAnnotation();
        //判断是否是接口类
        boolean isInterface = mClass.isInterface();
        //判断是否是枚举类
        boolean isEnum = mClass.isEnum();
        //判断是否是匿名内部类
        boolean isAnonymousClass=mClass.isAnonymousClass();
        //判断是否被某个注解类修饰
        boolean isAnnotationPresent=mClass.isAnnotationPresent(Deprecated.class);
        //获取class名字 包含包名路径
        String className = mClass.getName();
        //获取class的包信息
        Package aPackage = mClass.getPackage();
        //获取class类名
        String simpleName = mClass.getSimpleName();
        //获取class访问权限
        int modifiers = mClass.getModifiers();
        //内部类
        Class[] declaredClasses = mClass.getDeclaredClasses();
        //外部类
        Class declaringClass = mClass.getDeclaringClass();
    }

4.创建Class实例对象的方式

4.1通过newInstance()

这种方式也是我们常用的创建实体类的方式,调用静态方法使用类的默认构造方法创建。

4.2通过获取Constructor对象

先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。通过这种方式可以选择使用指定的构造器来创建实例。

两种创建方式的相关代码如下:


    /**
     * 通过Class获取类实例的方式
     * @param mClass
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public void getInstance(Class mClass) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //第一种方式 Class对象调用newInstance()方法生成
        StudentBean studentBean = null;
        studentBean = (StudentBean) mClass.newInstance();
        
        //第二种方式 对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成
        //获取指定声明构造函数
        Constructor constructor = null;
         constructor = mClass.getDeclaredConstructor(String.class, String.class,Integer.class);
      studentBean = (StudentBean) constructor.newInstance("小米", "男",20);
      
    }

4.调用类中的方法

相关代码如下:

  /**
     * 调用类中的方法
     */
   public void useMethod(){

       try {
           //获取Class
           Class studentClass =Class.forName("com.xzt.demo.bean.StudentBean");
           try {
               //创建Class实例
               StudentBean studentBean = (StudentBean) studentClass.newInstance();
               try {
                   //获取一个私有属性
                   Field field = null;
                   try {
                       field = studentClass.getDeclaredField("age");
                   } catch (NoSuchFieldException e) {
                       e.printStackTrace();
                   }
                   //将获取的私有属性设置在使用时应该取消Java语言的访问权限检查
                   field.setAccessible(true);
                   //根据参数获取指定方法
                   Method method=studentClass.getMethod("getPrivateAge", int.class);
                   //调用方法
                   Object str = null;
                   try {
                       str = method.invoke(studentBean, 20);
                       Log.e(TAG, "获取的年龄是:"+str);
                   } catch (InvocationTargetException e) {
                       e.printStackTrace();
                   }

               } catch (NoSuchMethodException e) {
                   e.printStackTrace();
               }
           } catch (IllegalAccessException e) {
               e.printStackTrace();
           } catch (InstantiationException e) {
               e.printStackTrace();
           }
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       }
   }

这里主要有两个知识点:

  • 我们通过invoke()方法来调用对应的方法。
  • 如果程序确实需要调用某个对象的private方法或私有属性,则可以先调用Method对象的setAccessible(boolean flag)方法。值为true,指示该Method在使用时应该取消Java语言的访问权限检查;值为false,则知识该Method在使用时要实施Java语言的访问权限检查。

5 通过反射运行配置文件内容

首先我们现在res/assets目录下新建一个reflect的文本文件如图:

Java-反射_第6张图片
image.png

StudentBean中要调用的方法:
Java-反射_第7张图片

相关代码如下

  /**
     * 通过反射运行配置文件内容
     */
    public void reflectXml() throws Exception{
        //通过反射获取Class对象
        Class stuClass = Class.forName(getValue("className"));
        //2获取配置文件中的getStudentMesage方法
        Method m = stuClass.getMethod(getValue("methodName"));
        //3.调用show()方法
        m.invoke(stuClass.getConstructor().newInstance());
    }
    //此方法接收一个key,在配置文件中获取相应的value
    public  String getValue(String key) throws IOException {
        //获取配置文件的对象
        Properties pro = new Properties();
        //获取输入流
        //FileReader in = new FileReader("reflect");
        InputStream in =this.getAssets().open("reflect");
        //将流加载到配置文件对象中
        pro.load(in);
        in.close();
        //返回根据key获取的value值
        return pro.getProperty(key);
    }

先这么多!

你可能感兴趣的:(Java-反射)