Android 反射

首先我们有一个如下的测试类-TestClassCtor

package com.chinatsp.javalib;
 
public class TestClassCtor {
    private String name;


    private static String address = "abc";

    public TestClassCtor() {
        name = "baobao";
    }

    public TestClassCtor(int a) {

    }

    public TestClassCtor(int a, String b) {
        name = b;
    }

    private TestClassCtor(int a, double c) {

    }

    private String doSOmething(String d) {
        Log.v("baobao", "TestClassCtor, doSOmething : " + d);

        return "abcd";
    }

    private static void work() {
        Log.v("baobao", "TestClassCtor, work");
    }

    public String getName() {
        return name;
    }

    public static void printAddress() {
        Log.v("baobao", address);
    }
}

接下来,我们通过反射来获取它的构造函数,以及公共/私有函数、属性等等

根据字符串得到一个类的对象

getClass

通过一个类的对象,获取它的类型。类型用Class表示:

String str = "abc";
Class c1 = str.getClass();
System.out.print(c1.getName());             // java.lang.String
Class.forName

这是我们常用来获取类型的方法`,通过类的命名空间和类的名称组成的字符串,获取该类的类型。

Class c1 = Class.forName("com.chinatsp.javalib.TestClassCtor");
System.out.print(c1.getName());             // com.chinatsp.javalib.TestClassCtor

获取一个类中的所有公共或私有、静态或实例的字段、方法以及属性

获取类的构造函数

包括public/private,包括无参/有参

Class c1 = Class.forName("com.chinatsp.javalib.TestClassCtor");
// 获取类的所有的构造函数
Constructor[] constructors = c1.getDeclaredConstructors();
......

// 获取类的所有的公共的public修饰的构造函数
Constructor[] constructors = c1.getConstructors();

// 获取类的某个有参的构造函数,这里以两个参数的构造器为例
Class[] p2 = {String.class,int.class};
Constructor c2 = c1.getDeclaredConstructor(p2);
......


// 获取类的无参的构造函数
Constructor c1 = c1.getDeclaredConstructor();
......
获取类的构造函数的修饰域及参数
Class c1 = Class.forName("com.chinatsp.javalib.TestClassCtor");
Class[] p2 = {String.class,int.class};
Constructor c2 = c1.getDeclaredConstructor(p2);
int mod = c2.getModifiers();   //输出修饰域 public
String constructorName = c2.getName();    // 输出方法名 com.chinatsp.javalib.TestClassCtor
Class[] parameterTypes = c2.getParameterTypes();  // 获取指定构造方法参数的集合
for(int j=0;j< parameterTypes.length;j++){
       // 输出打印参数列表
      System.out.print(parameterTypes[j].getName());     //   java.lang.String, int
       if(parameterTypes.length > j + 1) {
            System.out.print(", ");
       }
}
获取类的实例,通过newInstance()
  1. 通过构造函数获取类实例
// 获取有两个参数的构造函数
 Class c = Class.forName("com.chinatsp.javalib.TestClassCtor");
 Class[] p = {String.class,int.class};
Constructor ctor = c.getDeclaredConstructor(p3);
// 获取类实例,为两个参数的构造函数赋值
Object obj = ctor.newInstance("bjq",1);
 if(obj instanceof TestClassCtor){
       System.out.println("obj is TestClassCtor");
       TestClassCtor testClassCtor = (TestClassCtor) obj;
       System.out.println("testClassCtor.a = " + testClassCtor.getA() + ",name=" + testClassCtor.getName());
}
================================================================================
obj is TestClassCtor
testClassCtor.a = 1,name=bjq
==============================================================================


// 获取无参的构造函数
Constructor ctor1 = c.getDeclaredConstructor();
Object obj1 = ctro1.newInstance();
 if(obj1 instanceof TestClassCtor){
       System.out.println("obj1 is TestClassCtor");
       TestClassCtor testClassCtor1 = (TestClassCtor) obj1;
       System.out.println("testClassCtor1.a = " + testClassCtor1.getA() + ",name=" + testClassCtor1.getName());
}
================================================================================
obj1 is TestClassCtor
testClassCtor1.a = 0,name=baobao
==============================================================================

  1. 使用Class.newInstance()

如果构造函数是无参的,可以直接使用Class的newInstance方法创建类实例

Class c = Class.forName("com.chinatsp.javalib.TestClassCtor");
Object obj2 = c.newInstance();
 if(obj2 instanceof TestClassCtor){
       System.out.println("obj2 is TestClassCtor");
       TestClassCtor testClassCtor2 = (TestClassCtor) obj2;
       System.out.println("testClassCtor2.a = " + testClassCtor2.getA() + ",name=" + testClassCtor2.getName());
}
================================================================================
obj2 is TestClassCtor
testClassCtor2.a = 0,name=baobao
==============================================================================
获取类的私有方法并调用它

TestClassCtor中,有一个私有方法doSomething,想获取这个私有方法并执行它,可以如下:

// 获取类实例
 Class c = Class.forName("com.chinatsp.javalib.TestClassCtor");
Object obj = c.newInstance();
// 以下五行代码获取private方法并调用该private方法
 Class[] p = {String.class}; // doSomething()需要一个字符串参数
 Method method = c.getDeclaredMethod("doSomething", p); // 在指定类中获取指定方法
method.setAccessible(true);
Object argList[] = {"jianqiang"};
Object result = method.invoke(objCtor,argList);

System.out.println(result);


================================================================================
TestClassCtro,doSomething : jianqiang
abcd
================================================================================
获取类的静态私有方法并调用它

TestClassCtro中,有一个静态的私有方法work:

Class r2 = Class.forName("com.chinatsp.javalib.TestClassCtor");
Method method2 = r2.getDeclaredMethod("work");
method2.setAccessible(true);
method2.invoke(null);

================================================================================
TestClassCtor, work
================================================================================

获取类的私有实例字段并修改它

在TestClassCtro中,有一个私有的实例字段name

// 获取类实例
Class c = Class.forName("com.chinatsp.javalib.TestClassCtor");
Class[] p = {int.class, String.class};
Constructor ctor = c.getDeclaredConstructor(p);
Object obj = ctor.newInstance(1, "bjq");

// 获取name字段
Field field = c.getDeclaredField("name");
field.setAccessible(true);
// 获取了obj对象,此时是TestClassCtor对象中的name字段
// 方法:get(Object obj) 返回指定对象obj上此 Field 表示的字段的值,此处不能是null
Object fieldObject = field.get(obj);
if(fieldObject instanceof String){
      String name = (String) fieldObject;
      System.out.println(name);                //  bjq
}

// 修改name字段的值,注意是obj实例中的name
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
field.set(obj, "jianqiang1982");
Object fieldObject1 = field.get(obj);
if(fieldObject1 instanceof String){
      String name = (String) fieldObject1;
      System.out.println(name);             //  jianqiang1982
}
获取类的私有静态字段并修改它

在TestClassCtro中,有一个静态的私有字段address,想获取它并修改它的值

Class r = Class.forName("com.chinatsp.javalib.TestClassCtor");
Field field = r.getDeclaredField("address");
field.setAccessible(true);
// 传入任何对象都可以
Object fieldObject = field.get(null);
field.set(fieldObject,"ABCD");
TestClassCtro.printAddress();      // ABCD

注意

我们在获取私有静态字段和私有非静态字段时略有不同。
如果字段是非静态字段的话, field.get(Object obj);方法中传入的对象参数要传入反射类的对象,如果传null是会报java.lang.NullPointerException
如果字段是静态字段的话,传入任何对象都是可以的,包括null

对泛型类的反射

看以下的单例类Singleton

package com.chinatsp.javalib;

public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

Singleton是一个泛型类,也是一个抽象类,AMN.class是对它的实现:

package com.chinatsp.javalib;

public class AMN {
    private static final Singleton<ClassB2Interface> gDefault = new Singleton<ClassB2Interface>() {
        @Override
        protected ClassB2Interface create() {
            ClassB2 b2 = new ClassB2();
            b2.id = 2;
            return b2;
        }
    };

    static public ClassB2Interface getDefault(){
        return gDefault.get();
    }

    static public void fun(){

    }
}

上面的代码中gDefault是AMN的静态私有变量,它是Singleton类型的,所以要实现create()方法,返回一个ClassB2类型的对象,ClassB2的实现如下:

package com.chinatsp.javalib;

public class ClassB2 implements ClassB2Interface{
    public int id;
    @Override
    public void doSomething() {
        System.out.println("ClassB2 doSomething");
    }
}

ClassB2实现了ClassB2Interface接口,ClassB2Interface类:

package com.chinatsp.javalib;

public interface ClassB2Interface {
   public void doSomething();
}

Singleton是一个泛型,对于它,我们可以通过如下代码获取Singleton中的mInstance字段;

// 获取Singleton中的mInstance字段
Class<?> singleton = Class.forName("com.chinatsp.javalib.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);

Class<?> activityManagerNativeClass = Class.forName("com.chinatsp.javalib.AMN");
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
// 获取到gDefault字段的值,此时代表的是一个Singleton<ClassB2Interface>对象
Object gDefault = gDefaultField.get(null);

//AMN 的gDefault 对象里面原始的B2对象
// 获取gDefault中的mInstance字段的值,此时是ClassB2对象
Object rawB2Object = mInstanceField.get(gDefault);
if(rawB2Object instanceof ClassB2){
  	System.out.println("rawB2Object is ClassB2");        
}
注意

要获取到gDefault中的ClassB2对象,(也就是mInstanceField.get(gDefault);获取的值)需要先执行AMN.getDefault().doSomething();,这行代码是为了给gDefault中的mInstance字段赋值,调用AMN的getDefault()将会调用到Singleton的get方法,再调用到Singletoncreate方法,再调用到AMN中gDefaultcreate方法返回一个ClassB2对象

猜你喜欢

转载自blog.csdn.net/jxq1994/article/details/130557411