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等,我们运行的结果如下:


    image.png
  • Class.getFields(),此方法只能获取Public的属性数组,我们运行结果如下:


    image.png
  • Class.getDeclaredField("属性名"),获取指定属性,包括Private和Public等,如图:
    image.png
  • Class.getField("属性名");词方法获取公共的属性,不包括Private属性。如下:


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


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的文本文件如图:

image.png

StudentBean中要调用的方法:

相关代码如下

  /**
     * 通过反射运行配置文件内容
     */
    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);
    }

先这么多!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容

  • 深入理解Class对象 RRTI的概念以及Class对象作用 认识Class对象之前,先来了解一个概念,RTTI(...
    架构师springboot阅读 1,561评论 0 3
  • 一、概述 Java反射机制定义 Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法...
    CoderZS阅读 1,634评论 0 26
  • 1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以让我们在运行时获取类的函数、...
    Ten_Minutes阅读 537评论 0 4
  • 平时看到一些好的点会整理记录,但是还没有连成一条线。等到积累够多,会试着连成一条线。让自己的知识脉络更清晰。 写完...
    love丁酥酥阅读 197评论 0 0
  • 有个哲人说,而若爱千古,尔当爱现在。 在坐标上,时间分三个部分,过去,现在和未来。 过去至追溯到无穷,未来也延伸到...
    金萝阅读 383评论 0 2