首先我们有一个如下的测试类-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()
- 通过构造函数获取类实例
// 获取有两个参数的构造函数
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
==============================================================================
- 使用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方法,再调用到Singleton
的create
方法,再调用到AMN中gDefault
的create
方法返回一个ClassB2
对象