JAVA反射系列之 构造函数,方法,属性反射详解

2 篇文章 0 订阅
1 篇文章 0 订阅

一 前言

上篇博客我们讲了 Class 类,也是为本篇做铺垫的。下面进入正文

1.1反射机制是什么?

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

1.2为什么要用反射机制?反射机制优缺点。

为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态编译的概念,
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。

  • 优点:就是可以实现动态创建对象和编译,体现出很大的灵活性。
  • 缺点:对性能有影响。反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多。
1.3反射机制能做什么?
  • 生成动态代理(下篇我们会说动态代理);
  • 插件化中用到了大量的反射;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个对象所属的类;
  • 等等。

二 构造函数,方法,属性反射详解

2.1 构造函数反射

获得构造函数的方法

    //根据指定参数获得public构造器
    Constructor getConstructor(Class[] params);
    //获得public的所有构造器
    Constructor[] getConstructors();
    //根据指定参数获得public和非public的构造器
    Constructor getDeclaredConstructor(Class[] params);
    //获得public的所有构造器 
    Constructor[] getDeclaredConstructors();

看这些方法如何使用,先来个Student类供我们反射使用

public class Student {

    private static String TAG = Student.class.getSimpleName();
    public int age;
    private String name;

    public Student() {
        age = 20;
        name = "小明";
    }

    public Student(int age, String name) {
        Log.e(TAG, "Student: " + "age " + age + " name " + name);
    }

    public void StudentA() {
        Log.e(TAG, "StudentA: ");
    }

    public void StudentA(int age) {
        Log.e(TAG, "StudentA: " + "age " + age);
    }

    public void StudentA(int age, String name) {
        Log.e(TAG, "StudentA: " + "age " + age + " name " + name);
    }
}
1. 获得public的所有构造器Constructor[] getConstructors();使用如下
        //通过 包名+类名 获取 Student类类型
        Class c = Class.forName("zhangqilu.com.plugin.Student");
        //获得public的所有构造器
        Constructor[] constructors = c.getConstructors();
        for (Constructor con:constructors) {
            String constructorName = con.getName();
            System.out.print(constructorName+"(");
            //获得构造函数的所有参数
            Class[] classType = con.getParameterTypes();
            for (int i = 0; i <classType.length ; i++) {
                if(i==classType.length-1){
                    System.out.print(classType[i].getName());
                }else{
                    System.out.print(classType[i].getName()+",");
                }
            }
            System.out.println(")");
        }

控制台打印日志如下:

03-08 19:02:21.051 17440-17440/zhangqilu.com.plugin I/System.out: zhangqilu.com.plugin.Student()
03-08 19:02:21.051 17440-17440/zhangqilu.com.plugin I/System.out: zhangqilu.com.plugin.Student(int,java.lang.String)

打印出2个构造函数,一个是没有参数构造函数Student()
另一个是有2个参数(int和String类型)的构造函数 Student(int,java.lang.String)

2. 根据指定参数获得public构造器Constructor getConstructor(Class[] params);

Class[] params 构造函数的参数类型 的 类类型
使用如下

//通过 包名+类名 获取 Student类类型
            Class stuentClass = Class.forName("zhangqilu.com.plugin.Student");
//通过 Student类类型获取 构造函数 int.class, String.class 构造函数的参数类型 的 类类型
            Constructor constructor = stuentClass.getConstructor(int.class, String.class);
//创建Student类实例  构造函数参数 age 100   name dog
            Object object = constructor.newInstance(100, "dog");

控制台打印日志如下:

03-08 19:54:13.029 25292-25292/? E/Student: Student: age 100 name dog

构造函数的反射主要就2种情况,1是获取所有构造函数, 2是根据指定参数获取构造函数。下面我们来看看方法的反射。

2.2方法反射

获得类方法的方法
Method getMethod(String name, Class[] params),根据方法名,参数类型获得方法

    //获得所有的public方法包括父类继承而来的
    Method[] getMethods();
    //根据方法名和参数类型,获得public和非public的方法
    Method getDeclaredMethod(String name, Class[] params);
    Method[] getDeclaredMethods()//获得所以的public和非public方法 ;
1.获得所有的public方法包括父类继承而来的Method[] getMethods();使用如下.
            Class c = Class.forName("zhangqilu.com.plugin.Student");//通过 包名+类名 获取 Student类类型;
            Method[] methods = c.getMethods();//获得所有的public方法 包括父类继承而来的;
            for (int i = 0; i < methods.length; i++) {
                Class returnType = methods[i].getReturnType();//方法的返回值类型
                System.out.print(returnType.getName()+ " " );
                System.out.print(methods[i].getName()+ "(" );//获得方法的名字
                Class[] paramTypes = methods[i].getParameterTypes();//方法所有参数
                for (int j = 0; j < paramTypes.length; j++) {
                    if(j==paramTypes.length-1){                       System.out.print(paramTypes[j].getName());
                    }else {                     System.out.print(paramTypes[j].getName()+",");
                    }
                }
                System.out.println(")" );//获得方法的名字
            }

控制台打印日志如下

03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA()
03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA(int)
03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA(int,java.lang.String)
03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.Object access$super(zhangqilu.com.plugin.Student,java.lang.String,[Ljava.lang.Object;)
03-09 10:41:45.392 10495-10495/? I/System.out: boolean equals(java.lang.Object)
03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.Class getClass()
03-09 10:41:45.392 10495-10495/? I/System.out: int hashCode()
03-09 10:41:45.392 10495-10495/? I/System.out: void notify()
03-09 10:41:45.392 10495-10495/? I/System.out: void notifyAll()
03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.String toString()
03-09 10:41:45.392 10495-10495/? I/System.out: void wait()
03-09 10:41:45.392 10495-10495/? I/System.out: void wait(long)
03-09 10:41:45.392 10495-10495/? I/System.out: void wait(long,int)
2.根据方法名和参数类型,获得public和非public的方法
Method getDeclaredMethod(String name, Class[] params);
参数含义:
name   方法名
Class[] params   方法的参数类型 的 类类型

我们还要看一个反射的重要方法

public Object invoke(Object obj,Object... args)

参数理解:
obj 反射方法的对象(调用谁的方法用谁的对象)
如果方法为 静态的 obj 可以为null
args 用于方法调用的参数

体使用如下:

            Class studentClass = Class.forName("zhangqilu.com.plugin.Student");//通过 包名+类名 获取 Student 类类型;
            Object object = studentClass.newInstance();//获取Student 实例;          Method method = studentClass.getMethod("StudentA", int.class, String.class);//根据方法名和参数类型获取方法实例;
method.invoke(object, 20, "zhangqilu");//反射执行方法

控制台打印日志如下

03-09 16:02:55.082 2372-2372/zhangqilu.com.plugin E/Student: StudentA: age 20 name zhangqilu
2.3 属性反射

获得类中属性的方法

    //根据变量名得到相应的public变量
    Field getField(String name)
    //获得类中所以public的方法
    Field[] getFields()
    //根据方法名获得public和非public变量
    Field getDeclaredField(String name)
    //获得类中所有的public和非public方法 
    Field[] getDeclaredFields()

属性反射和构造函数和方法反射类似,我们只说

 Field getDeclaredField(String name)

使用。

            Class stuentClass = Class.forName("zhangqilu.com.plugin.Student");
            Object object = stuentClass.newInstance();
            Field field = stuentClass.getField("age");
            int age = (int) field.get(object);
            Log.e(TAG, "reflectionField: age " + age);
            Field field1 = stuentClass.getDeclaredField("name");
             /*
            Java代码中,常常将一个类的成员变量置为private
            在类的外面获取此类的私有成员变量的value时,需要注意:
            将field.setAccessible(true);
             */
            field1.setAccessible(true);
            String name = (String) field1.get(object);
            Log.e(TAG, "reflectionField: name " + name);

控制台打印日志如下。

03-09 16:19:54.337 14194-14194/zhangqilu.com.plugin E/MainActivity: reflectionField: age 20
03-09 16:19:54.338 14194-14194/zhangqilu.com.plugin E/MainActivity: reflectionField: name 小明

反射就说到这里,下一篇我们讲代理(静态代理和动态代理)。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值