平常在写java程序的时候,有时会用到一些方法,但是在IDE中调用不到这些方法,进入到源码中,会发现这些方法的上面有@hide标识,这表示这些是被隐藏的
还有在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放
如果想调用这些方法只能通过反射来进行调用
与Java反射相关的类如下:
序号 | 类名 | 用途 |
---|---|---|
1 | Class | 代表类的实体,在运行的Java应用程序中表示类和接口 |
2 | Field | 代表类的成员变量 |
3 | Method | 代表类的方法 |
4 | Constructor | 代表类的构造方法 |
获得类相关的方法
序号 | 获取类方法 | 用途 |
---|---|---|
1 | asSubclass(Class<U> clazz) | 把传递的类的对象转换成代表其子类的对象 |
2 | Cast | 把对象转换成代表类或是接口的对象 |
3 | getClassLoader() | 获得类的加载器 |
4 | getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 |
5 | getDeclaredClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 |
6 | forName(String className) | 根据类名返回类的对象 |
7 | getName() | 获得类的完整路径名字 |
8 | newInstance() | 创建类的实例 |
9 | getPackage() | 获得类的包 |
10 | getSimpleName() | 获得类的名字 |
11 | getSuperclass() | 获得当前类继承的父类的名字 |
1 2 | getInterfaces() | 获得当前类实现的类或是接口 |
获得类构造器的方法
序号 | 构造方法 | 用途 |
---|---|---|
1 | getConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
2 | getConstructors() | 获得该类的所有公有构造方法 |
3 | getDeclaredConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
4 | getDeclaredConstructors() | 获得该类所有构造方法 |
获得注解的方法
序号 | 获取注解方法 | 用途 |
---|---|---|
1 | getAnnotation(Class<A> annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
2 | getAnnotations() | 返回该类所有的公有注解对象 |
3 | getDeclaredAnnotation(Class<A> annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
4 | getDeclaredAnnotations() | 返回该类所有的注解对象 |
获得属性的方法
序号 | 获取属性方法 | 用途 |
---|---|---|
1 | getField(String name) | 获得某个公有的属性对象 |
2 | getFields() | 获得所有公有的属性对象 |
3 | getDeclaredField(String name) | 获得某个属性对象 |
4 | getDeclaredFields() | 获得所有属性对象 |
获得方法的方法
序号 | 获取属性方法 | 用途 |
---|---|---|
1 | getMethod(String name, Class...<?> parameterTypes) | 获得该类某个公有的方法 |
2 | getMethods() | 获得该类所有公有的方法 |
3 | getDeclaredMethod(String name, Class...<?> parameterTypes) | 获得该类某个方法 |
4 | getDeclaredMethods() | 获得该类所有方法 |
栗子
创建一个对象类,,有两个构造方法,一个public方法 一个static方法 一个private方法
public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public Person() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "toString=name="+name+",age="+age;
}
private String myToString(){
return "myToString=name="+name+",age="+age;
}
public static String staticToString(){
return "static.tostring";
}
}
调用反射获取它
private void reflex1() throws Exception{
//获取类对象
Class calzz=Class.forName("com.example.testreflex.Person");
//获取无参构造方法
Constructor constructor1=calzz.getConstructor();
//获取类中变量
Field name =calzz.getDeclaredField("name");
Field age =calzz.getDeclaredField("age");
//允许方位私有变量
name.setAccessible(true);
age.setAccessible(true);
//用无参构造函数,实例化对象
Object object1=constructor1.newInstance();
//反射获得类中方法
Method method=calzz.getMethod("setAge",age.getType());
Method method2=calzz.getMethod("setName",name.getType());
Method method3=calzz.getMethod("toString");
//执行类中的set方法
method.invoke(object1,10);
method2.invoke(object1,"Hello");
String text2= (String) method3.invoke(object1);
//进行打印
Log.i("info","person.tostring="+text2);
}
private void reflex2() throws Exception{
// 获取类对象
Class calzz=Class.forName("com.example.testreflex.Person");
Field name =calzz.getDeclaredField("name");
Field age =calzz.getDeclaredField("age");
name.setAccessible(true);
age.setAccessible(true);
//获取有参的构造方法
Constructor constructor2=calzz.getConstructor(age.getType(),name.getType());
//实例化对象
Object object2=constructor2.newInstance(11,"hello2");
//获取类中的方法
Method method3=calzz.getMethod("toString");
//获取私有方法
Method method4=calzz.getDeclaredMethod("myToString");
method4.setAccessible(true);
String text= (String) method3.invoke(object2);
String test2= (String) method4.invoke(object2);
Log.i("info","person2.tostring="+text);
Log.i("info","person2.tostring="+test2);
//获取静态方法
Method method5=calzz.getDeclaredMethod("staticToString");
String test3= (String) method5.invoke(method5);
Log.i("info","person2.tostring="+test3);
}
输出的打印日志
I/info: person.tostring=toString=name=Hello,age=10
I/info: person.tostring=toString=name=hello2,age=11
I/info: person2.tostring=myToString=name=hello2,age=11
I/info: person3.tostring=static.tostring
在实际工作中的例子,获取EthernetManager及EthernetDevInfo
EthernetManager是个隐藏类,之前我们公司用的IP电话需要使用这个类,余是我就给他反射出来了
1.实例化EthernatManager
private Class<?> ethernetManager; //未实例化类对象
private Object objEthernetManager;//实例化对象
private Class<?> ethernetDevInfo;
private Object objEthernetDevInfo;
/** EthernetManager mEthManager = (EthernetManager)
getSystemService(Context.ETHERNET_SERVICE);
*这个是正常初始化调用的模式
*/
//在实际工作中获取类
ethernetManager = Class.forName("android.net.ethernet.EthernetManager");
//获取Contexct属性ETHERNET_SERVICE这个是被隐藏的
Class<?> context = Class.forName("android.content.Context");
Field f = context.getField("ETHERNET_SERVICE");
String ETHERNET_SERVICE = (String) f.get(context);
//实例化EthernetManager
objEthernetManager = context
.getSystemService(ETHERNET_SERVICE);
//接下来需要实例化 EthernetDevInfo 这个类 下面是正常的调用方式
// EthernetDevInfo mInterfaceInfo = mEthManager.getSavedConfig();
//EthernetDevInfo通过EthernetManager的getSavedConfig()方法进行初始化
//获取EthernetManager中的getSavedConfig方法
Method getSavedConfig = ethernetManager
.getDeclaredMethod("getSavedConfig");
ethernetDevInfo = Class
.forName("android.net.ethernet.EthernetDevInfo");//获取EthernetDevInfo类
objEthernetDevInfo = getSavedConfig.invoke(objEthernetManager);//执行mEthManager.getSavedConfig()方法
调用SystemProperties的get set方法
SystemProperties同样也是系统的隐藏类,直接调用是调用不到的
Class<?> mClassType = Class.forName("android.os.SystemProperties");
Method getMethod = mClassType
.getDeclaredMethod("get", String.class);
value = (String) getMethod.invoke(mClassType, key);
Method getMethod = mClassType
.getDeclaredMethod("set", String.class);
value = (String) getMethod.invoke(mClassType, key);
调用构造函数RouteInfo
// 获得了路由信息类
Class<?> routeInfoClass = Class.forName("android.net.RouteInfo");
// 获得路由信息类的一个构造器,参数是网关
Constructor<?> routeInfoConstructor = routeInfoClass
.getConstructor(new Class[] { InetAddress.class });
// 生成指定网关的路由信息类对象
Object routeInfo = routeInfoConstructor.newInstance(gateWay);
接下来我将用jni方法反射出person类中的属性和方法
jni方法的相关介绍请看我另一篇文章
[JNI方法的汇总](https://www.jianshu.com/p/4334f084b2a4)
jni部分我直接上的代码,下面是我的目录结构
利用javaP反射出person中的目录结构
javap -classpath E:\StudioProjects\TestReflex\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes -p -s com.example.testreflex.Person
Compiled from "Person.java"
public class com.example.testreflex.Person {
private int age;
descriptor: I
private java.lang.String name;
descriptor: Ljava/lang/String;
private byte[] b;
descriptor: [B
public com.example.testreflex.Person(int, java.lang.String);
descriptor: (ILjava/lang/String;)V
public com.example.testreflex.Person();
descriptor: ()V
public int getAge();
descriptor: ()I
public void setAge(int);
descriptor: (I)V
public java.lang.String getName();
descriptor: ()Ljava/lang/String;
public void setName(java.lang.String);
descriptor: (Ljava/lang/String;)V
public java.lang.String toString();
descriptor: ()Ljava/lang/String;
private java.lang.String myToString();
descriptor: ()Ljava/lang/String;
public static java.lang.String staticToString();
descriptor: ()Ljava/lang/String;
public byte[] getB();
descriptor: ()[B
public void setB(byte[]);
descriptor: ([B)V
}
Process finished with exit code 0
在NDKReflex.java文件中创建 reflex1 reflex2 reflex3三个方法
reflex1 为创建无参构造函数 然后利用set方法设置属性,最后输出
reflex2 为创建有参构造函数然后输出
reflex3 为创建无参构造函数 获取person中的变量,最后输出修改变量后的方法
public class NDKReflex {
static {
System.loadLibrary("reflex-lib");
}
public native void reflex1();
public native void reflex2();
public native void reflex3();
}
reflex1方法 创建无参构造函数 然后利用set方法设置属性,最后输出
void printJstring(JNIEnv *env,jstring string){
const char * c_name = env->GetStringUTFChars(reinterpret_cast<jstring>(string), NULL);//转换成 char *
LOGI("%s",c_name);
}
JNIEXPORT void JNICALL Java_com_example_testreflex_NDKReflex_reflex1
(JNIEnv *env, jobject object){
jclass clazz=env->FindClass("com/example/testreflex/Person");
//"<init>"为构造方法标识
LOGI("reflex1");
jmethodID init1 = env->GetMethodID(clazz, "<init>", "()V");//无参构造函数
jmethodID setAge= env->GetMethodID(clazz , "setAge","(I)V");//获取setAge方法
jmethodID setName= env->GetMethodID(clazz , "setName","(Ljava/lang/String;)V");//设置setName方法
jmethodID toString= env->GetMethodID(clazz , "toString","()Ljava/lang/String;");//获取toString方法
jmethodID myToString= env->GetMethodID(clazz , "myToString","()Ljava/lang/String;");//获取myToString方法
jmethodID staticToString= env->GetStaticMethodID(clazz , "staticToString","()Ljava/lang/String;");//获取静态staticToString方法
jobject obj=env->NewObject(clazz,init1);//实例化Person对象
env->CallVoidMethod(obj,setAge,10);//person.setAge(10)
env->CallVoidMethod(obj,setName,env->NewStringUTF("I"));//person.setName("I")
jstring jtoString= reinterpret_cast<jstring>(env->CallObjectMethod(obj, toString));
printJstring(env,jtoString);//toString
jstring jMyString= reinterpret_cast<jstring>(env->CallObjectMethod(obj, myToString));
printJstring(env,jMyString);//myToString
jstring jstaticToString= reinterpret_cast<jstring>(env->CallStaticObjectMethod(clazz, staticToString));
printJstring(env,jstaticToString);//saticToString
}
reflex2方法 创建有参构造函数然后输出
JNIEXPORT void JNICALL Java_com_example_testreflex_NDKReflex_reflex2
(JNIEnv *env, jobject object){
jclass clazz=env->FindClass("com/example/testreflex/Person");
//"<init>"为构造方法标识
LOGI("reflex2");
jmethodID init1 = env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");//有参构造函数 int String
jmethodID toString= env->GetMethodID(clazz , "toString","()Ljava/lang/String;");//获取toString方法
jmethodID myToString= env->GetMethodID(clazz , "myToString","()Ljava/lang/String;");//获取myToString方法
jmethodID staticToString= env->GetStaticMethodID(clazz , "staticToString","()Ljava/lang/String;");//获取静态staticToString方法
jobject obj=env->NewObject(clazz,init1,43,env->NewStringUTF("My Father"));//new Person(43,"My Father")
jstring jtoString= reinterpret_cast<jstring>(env->CallObjectMethod(obj, toString));
printJstring(env,jtoString);//toString
jstring jMyString= reinterpret_cast<jstring>(env->CallObjectMethod(obj, myToString));
printJstring(env,jMyString);//myToString
jstring jstaticToString= reinterpret_cast<jstring>(env->CallStaticObjectMethod(clazz, staticToString));
printJstring(env,jstaticToString);//saticToString
}
reflex3方法 创建无参构造函数 获取person中的变量,最后输出修改变量后的方法
JNIEXPORT void JNICALL Java_com_example_testreflex_NDKReflex_reflex3
(JNIEnv *env, jobject object){
jclass clazz=env->FindClass("com/example/testreflex/Person");
//"<init>"为构造方法标识
LOGI("reflex3");
jmethodID init1 = env->GetMethodID(clazz, "<init>", "()V");//无参构造函数
jfieldID age=env->GetFieldID(clazz,"age","I");
jfieldID name=env->GetFieldID(clazz,"name","Ljava/lang/String;");
jmethodID toString= env->GetMethodID(clazz , "toString","()Ljava/lang/String;");//获取toString方法
jmethodID myToString= env->GetMethodID(clazz , "myToString","()Ljava/lang/String;");//获取myToString方法
jmethodID staticToString= env->GetStaticMethodID(clazz , "staticToString","()Ljava/lang/String;");//获取静态staticToString方法
jobject obj=env->NewObject(clazz,init1);//new Person()
env->SetIntField(obj,age,40); //age = 40;
env->SetObjectField(obj,name,env->NewStringUTF("My Mother"));//name=My Mother
jstring jtoString= reinterpret_cast<jstring>(env->CallObjectMethod(obj, toString));
printJstring(env,jtoString);//toString
jstring jMyString= reinterpret_cast<jstring>(env->CallObjectMethod(obj, myToString));
printJstring(env,jMyString);//myToString
jstring jstaticToString= reinterpret_cast<jstring>(env->CallStaticObjectMethod(clazz, staticToString));
printJstring(env,jstaticToString);//saticToString
}
输出的结果
10-03 13:44:19.991 5847-5847/com.example.testreflex I/myReflex-jni: reflex1
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: toString mothed,name=I,age=10
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: myToString mothed,name=I,age=10
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: static.tostring
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: reflex2
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: toString mothed,name=My Father,age=43
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: myToString mothed,name=My Father,age=43
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: static.tostring
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: reflex3
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: toString mothed,name=My Mother,age=40
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: myToString mothed,name=My Mother,age=40
10-03 13:44:19.992 5847-5847/com.example.testreflex I/myReflex-jni: static.tostring