Android进阶篇 - 反射机制

前言

都知道反射技术很厉害,对我们开发过程中的帮忙也特别大。而且在阅读源码的过程中也不难发现里面有很多地方都用到了反射。今天把最近了解到的反射技术简单记录一下。

反射(ReFlect)

  • 概念

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

简单来讲就是:可以访问、检测和修改它本身状态或行为的一种能力。

  • 作用

反编译:将 class 文件反编译成 Java 文件。
访问对象:访问 Java 对象中的属性、方法、构造方法等。

  • 核心的类

java.lang.Class - 类,某个具体的类或接口
java.lang.reflect.Constructor - 反射构造方法
java.lang.reflect.Field - 反射属性
java.lang.reflect.Method - 反射方法
java.lang.reflect.Modifier - 访问修饰符的信息

Class:Class对象是一个特殊的对象,是用来创建其它Java的实例,Class对象就是Java类编译后生成的.class文件,它包含了与类有关的信息。
Field:Filed字段提供有关和动态访问的信息,类或接口的单个字段。反射的字段可能是类字段或实例字段。
Method:Method方法提供了关于单个方法的信息和访问在类或接口上。反射的方法可能是类方法或者是一个实例方法(包括一个抽象的方法)。
Constructor:Constructor提供了关于某类的构造方法的所需信息。
Modifier: 获取修饰符的类型

  • 核心API

getClass() - 获取类
getAnnotation(xx.class) - 获取注解
getConstructor(Class[])- 根据构造函数的参数,返回一个具体的具有public属性的构造函数
getConstructors() 返回所有具有public属性的构造函数数组
getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
getDeclaredConstructors()返回该类中所有的构造函数数组(不分public和非public属性)
getMethod() - 获取方法 [1.获取当前类的方法 2.获取public的方法]
invoke(obj,yy) - 执行方法 [method.invoke(对象,参数)]
getDeclaredMethods() - 获取所有方法 [1.获取当前类和父类的方法 2.获取任何修饰的方法]
getDeclaredFields() - 获取所有属性
annotationType() - 获取注解的类型
setAccessible(true) - 设置私有变量/方法的访问权限
set(class, obj) - 赋值

  • 使用
  • 1.获取反射类的三种方式
// 方式一
Class c1 = Class.forName("com.test.java.Test");
// 方式二
Class c2 = Test.class;
//方式三
Test test = new Test();
Class c3 = test.getClass();

System.out.println(c1 + "\n" + c2 + "\n" + c3);

Log:
c1 ==> class com.test.java.Test
c2 ==> class com.test.java.Test
c3 ==> class com.test.java.Test

方式一:Class.forName 会让ClassLoader装载类,并进行类的初始化
方式二:xxx.class ClassLoader 装载入内存,不对类进行类的初始化操作
方式三:xxx.getClass 返回类对象运行时真正所指的对象,所属类型的Class对象
区别主要在于是否进行初始化和是否在实例中获取.

  • 2.获取反射类的构造函数
Class clazz = Test.class;
//方式一:
Constructor con1 = clazz.getConstructor(float.class);
System.out.println(con1);
//方式二:
Constructor[] con2 = clazz.getConstructors();
for (Constructor con : con2) {
   System.out.println(con);
}
//方式三:
Constructor con3 = clazz.getDeclaredConstructor(float.class, String.class);
System.out.println(con3);
//方式四:
Constructor[] con4 = clazz.getDeclaredConstructors();
for (Constructor con : con4) {
    System.out.println(con);
}

Log:
con1 ==> public com.test.java.Test(float)

con2 ==> public com.test.java.Test(float,java.lang.String)
con2 ==> public com.test.java.Test(float)
con2 ==> public com.test.java.Test()

con3 ==> public com.test.java.Test(float,java.lang.String)

con4 ==> public com.test.java.Test(float,java.lang.String)
con4 ==> public com.test.javaTest(float)
con4 ==> public com.test.java.Test()

方式一:getConstructor(Class[] params) 根据构造函数的参数,返回一个具体的具有public属性的构造函数
方式二:getConstructors()返回所有具有public属性的构造函数数组
方式三:getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数不分public和非public属性
方式四:getDeclaredConstructors() 返回该类中所有的构造函数数组不分public和非public属性

  • 3.获取反射类的对象
// 方式一:无参构造创建对象
Test t1 = Test.class.newInstance();
// 方式二:有参构造创建对象
 Test t2 = (Test) con1.newInstance(100f);

System.out.println(t1 + "\n" + t2);
Log:
t1 ==> com.test.java.Test@2503dbd3
t2 ==> com.test.java.Test@4b67cf4d

newInstance() 方法返回的是一个泛型T,需要强转成相应的反射类。
反射创建对象,可以使用Class.newInstance()Constructor.newInstance()两种方式
方式一必须要求反射类中存在一个无参的构造方法,并且有访问权限。
方式二适应各种类型的构造方法,无论是否有参数都可以调用,需要提供 setAccessible()控制访问验证即可。

  • 4.获取反射类的其他成员 (方法、属性)
public class Test {
  private float mHight = 100f;
  // 构造函数
  public Test() {
     System.out.println("Test中打印:测试反射");
  }
  private void logHight() {
     System.out.println("Test中打印mHight = " + mHight);
  }
  public void logHight(float mHight) {
     this.mHight = mHight;
     System.out.println("Test中打印赋值的mHight = " + mHight);
  }
}

// 获取反射类
Class clazz = Test.class;
// 获取反射类的对象
Test test = clazz.newInstance();

// 获取Test类中private申明的mHight变量
Field field = clazz.getDeclaredField("mHight");
// 允许访问私有成员变量
field.setAccessible(true);
System.out.println("field ==> " + field);

// 获取Test类中private申明的logHight()方法
Method method1 = clazz.getDeclaredMethod("logHight");
// 设置私有变量/方法的访问权限
method1.setAccessible(true);
// 打印method1
System.out.println("method1 ==> " + method1);
// 执行该方法
method1.invoke(test);

// 获取Test类中public申明的有参logHight()方法
Method method2 = clazz.getDeclaredMethod("logHight", float.class);
// 打印method1
System.out.println("method2 ==> " + method2);
// 执行该方法
method2.invoke(test, 200f);

Log:
Test中打印:测试反射
field ==> private float com.test.java.Test.mHight
method1 ==> private void com.test.java.Test.logHight()
Test中打印mHight = 100.0
method2 ==> public void com.test.java.Test.logHight(float)
Test中打印赋值的mHight = 200.0

public修饰的方法可以直接通过clazz.getMetho()获取,
而被非public修饰的方法(private,protected 等)则需要clazz.getDeclaredMethods()获取,并且需要使用method.setAccessible(true)来打开权限。
而获取变量的方式则和获取方法的方式基本一致。

以上就是对反射机制ReFlect的使用总结以及简单使用。

你可能感兴趣的:(Android进阶篇 - 反射机制)