前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java-反射

Java-反射

作者头像
android_薛之涛
发布2018-12-25 15:14:00
4820
发布2018-12-25 15:14:00
举报

参考: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);
    }

先这么多!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.12.09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.定义
  • 2.获取Class对象的三种方式(Class 是反射的入口)
  • 3.反射查看信息
    • 3.1查看类属性
      • 3.2查看类方法
        • 3.3 类的构造方法
          • 3.4 获取类的其他信息的相关方法
          • 4.创建Class实例对象的方式
          • 4.1通过newInstance()
          • 4.2通过获取Constructor对象
          • 4.调用类中的方法
          • 5 通过反射运行配置文件内容
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档