android的反射機制及用Jni對java類的反射

平常在寫java程序的時候,有時會用到一些方法,但是在IDE中調用不到這些方法,進入到源碼中,會發(fā)現(xiàn)這些方法的上面有@hide標識,這表示這些是被隱藏的


image.png

還有在日常的第三方應用開發(fā)過程中,經常會遇到某個類的某個成員變量、方法或是屬性是私有的或是只對系統(tǒng)應用開放
如果想調用這些方法只能通過反射來進行調用

與Java反射相關的類如下:

序號 類名 用途
1 Class 代表類的實體,在運行的Java應用程序中表示類和接口
2 Field 代表類的成員變量
3 Method 代表類的方法
4 Constructor 代表類的構造方法

獲得類相關的方法

序號 獲取類方法 用途
1 asSubclass(Class<U> clazz) 把傳遞的類的對象轉換成代表其子類的對象
2 Cast 把對象轉換成代表類或是接口的對象
3 getClassLoader() 獲得類的加載器
4 getClasses() 返回一個數(shù)組,數(shù)組中包含該類中所有公共類和接口類的對象
5 getDeclaredClasses() 返回一個數(shù)組,數(shù)組中包含該類中所有公共類和接口類的對象
6 forName(String className) 根據類名返回類的對象
7 getName() 獲得類的完整路徑名字
8 newInstance() 創(chuàng)建類的實例
9 getPackage() 獲得類的包
10 getSimpleName() 獲得類的名字
11 getSuperclass() 獲得當前類繼承的父類的名字
1 2 getInterfaces() 獲得當前類實現(xiàn)的類或是接口

獲得類構造器的方法

序號 構造方法 用途
1 getConstructor(Class...<?> parameterTypes) 獲得該類中與參數(shù)類型匹配的公有構造方法
2 getConstructors() 獲得該類的所有公有構造方法
3 getDeclaredConstructor(Class...<?> parameterTypes) 獲得該類中與參數(shù)類型匹配的構造方法
4 getDeclaredConstructors() 獲得該類所有構造方法

獲得注解的方法

序號 獲取注解方法 用途
1 getAnnotation(Class<A> annotationClass) 返回該類中與參數(shù)類型匹配的公有注解對象
2 getAnnotations() 返回該類所有的公有注解對象
3 getDeclaredAnnotation(Class<A> annotationClass) 返回該類中與參數(shù)類型匹配的所有注解對象
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() 獲得該類所有方法

栗子

創(chuàng)建一個對象類,,有兩個構造方法,一個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);
       //用無參構造函數(shù),實例化對象
        Object object1=constructor1.newInstance();
       //反射獲得類中方法
        Method method=calzz.getMethod("setAge",age.getType());
        Method method2=calzz.getMethod("setName",name.getType());
        Method method3=calzz.getMethod("toString");
        //執(zhí)行類中的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);
       //獲取靜態(tài)方法
        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.png

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);//執(zhí)行mEthManager.getSavedConfig()方法

調用SystemProperties的get set方法

SystemProperties同樣也是系統(tǒng)的隱藏類,直接調用是調用不到的

            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);

調用構造函數(shù)RouteInfo

準備調用的RouteInfo構造方法
            // 獲得了路由信息類
            Class<?> routeInfoClass = Class.forName("android.net.RouteInfo");
            // 獲得路由信息類的一個構造器,參數(shù)是網關
            Constructor<?> routeInfoConstructor = routeInfoClass
                    .getConstructor(new Class[] { InetAddress.class });
            // 生成指定網關的路由信息類對象
            Object routeInfo = routeInfoConstructor.newInstance(gateWay);

接下來我將用jni方法反射出person類中的屬性和方法
jni方法的相關介紹請看我另一篇文章
[JNI方法的匯總](http://www.itdecent.cn/p/4334f084b2a4
jni部分我直接上的代碼,下面是我的目錄結構

工程結構.png

利用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文件中創(chuàng)建 reflex1 reflex2 reflex3三個方法
reflex1 為創(chuàng)建無參構造函數(shù) 然后利用set方法設置屬性,最后輸出
reflex2 為創(chuàng)建有參構造函數(shù)然后輸出
reflex3 為創(chuàng)建無參構造函數(shù) 獲取person中的變量,最后輸出修改變量后的方法

public class NDKReflex {

    static {
        System.loadLibrary("reflex-lib");
    }

    public native void reflex1();
    public native void reflex2();
    public native void reflex3();
}

reflex1方法 創(chuàng)建無參構造函數(shù) 然后利用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");//無參構造函數(shù)
      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;");//獲取靜態(tài)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方法 創(chuàng)建有參構造函數(shù)然后輸出

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");//有參構造函數(shù) 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;");//獲取靜態(tài)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方法 創(chuàng)建無參構造函數(shù) 獲取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");//無參構造函數(shù)
    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;");//獲取靜態(tài)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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,626評論 1 32
  • 整體Retrofit內容如下: 1、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李頭閱讀 4,798評論 2 12
  • 一、基礎知識:1、JVM、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機...
    殺小賊閱讀 2,559評論 0 4
  • 整理來自互聯(lián)網 1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)工具...
    Ncompass閱讀 1,616評論 0 6
  • 一:java概述: 1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)...
    慕容小偉閱讀 1,939評論 0 10

友情鏈接更多精彩內容