反射學習記錄

反射

  • 官方說明

Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.

  • 百度翻譯

反射通常由需要檢查或修改在Java虛擬機中運行的應用程序運行時行爲的程序使用。這是一個相對高級的特性,應該只由對語言基礎有很強掌握的開發人員使用。記住這個警告,反射是一種強大的技術,並且能夠使應用程序執行否則不可能執行的操作。

  • 那麼我們可以用反射做什麼呢?

我們可以通過使用類的反射來獲取私有屬性或者動態生成一個類來實現類的各種方法。


用來測試的類

MainActivity

package com.gjn.testproject;

public class MainActivity extends AppCompatActivity {
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test();
	}
	
	enum Sex {
        man,
        woman
    }

    interface InterFace {
        void dos();
    }

    abstract static class BaseClz implements InterFace {
        public Sex sex = Sex.man;
        protected String base = "base";
        private int n = 456;

        @Override
        public void dos() {
            Log.e("-s-", "BaseClz dos");
        }
    }

    static class Clz extends BaseClz {
        private static final int NUM = 777;
        public static String STR = "cccc";
        public String str = "clz.";
        private int num = 100;

        private Clz(String str) {
            this.str = str;
        }

        @Override
        public void dos() {
            Log.e("-s-", "Clz dos");
        }
    }
}

其中包括了一個枚舉Sex一個接口兩個內置類

Draw

package com.gjn.testproject.test;

public interface Draw {
    void draw();
}

Shape

package com.gjn.testproject.test;

import android.util.Log;

public class Shape implements Draw {
    public static final String SHAPE = "Shape";

    private String shape;
    private String x;
    public int num;
    public String s;

    public Shape() {
        shape = "null";
        x = "?x?";
        num = 777;
        s = "wo shi s";
    }

    public Shape(String shape) {
        this.shape = shape;
    }

    private Shape(String s, String xx){
        shape = s;
        x = xx;
    }

    private void xxx(){
        draw();
        Log.e("-s-", "xxx => " + x);
    }

    @Override
    public void draw() {
        Log.e("-s-", "draw " + shape);
    }

    public String getX() {
        return x;
    }

    public void setX(String x) {
        this.x = x;
    }
}

這一個接口和一個類就是正常的類,那麼我們就開始進行反射操作把!

Class

獲取類(Class)

獲取類(Class)的三種方法

  • Class.forName(String)
try {
    Class c1 = Class.forName("com.gjn.testproject.MainActivity$BaseClz");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

  • Object.getClass()
 Clz clz = new Clz("1");
 Class c2 = clz.getClass();
  • Class.class (其中Class爲類名)
Class c3 = Shape.class;

第一個方法是用途最大的。後面2種用途比較少。

java.lang.Class的常用方法說明

方法 說明
getName() 獲取Class的全名,可以用來調用Class.forName(String)生成類的
getSimpleName() 獲取Class的簡稱
getCanonicalName() 獲取Class的冠名 就是會將內部類的$改成.
getModifiers() 獲取Class的修飾符
getSuperclass() 獲取Class的父類
getDeclaringClass() 獲取Class的聲明類
getComponentType() 獲取Class的組件類型
getEnclosingClass() 獲取Class的關閉類
getInterfaces() 獲取Class的接口
getAnnotations() 獲取Class的全部註解(含繼承) 可以用getAnnotation(Class annotationClass)或者getAnnotation(Class<T> annotationClass)獲取某個註解
getDeclaredAnnotations() 獲取Class的全部註解(當前類不包括繼承)
getConstructors() 獲取Class的全部構造函數(含繼承) 可以用getConstructor(Class<?>... parameterTypes)獲取某個構造函數
getDeclaredConstructors() 獲取Class的全部構造函數(當前類不包括繼承) 可以用getDeclaredConstructor(Class<?>... parameterTypes)獲取某個構造函數
getMethods() 獲取Class的全部方法(含繼承) 可以用getMethod(String name, Class<?>... parameterTypes)獲取某個方法
getDeclaredMethods() 獲取Class的全部方法(當前類不包括繼承) 可以用getDeclaredMethod(String name, Class<?>... parameterTypes)獲取某個方法
getFields() 獲取Class的全部參數(含繼承) 可以用getField(String name)獲取某個參數
getDeclaredFields() 獲取Class的全部參數(當前類不包括繼承) 可以用getDeclaredField(String name)獲取某個參數

下面是開頭測試test()的所以代碼

    private void test() {
        try {
            Class c1 = Class.forName("com.gjn.testproject.MainActivity$BaseClz");
            Clz clz = new Clz("1");
            Class c2 = clz.getClass();
            Class c3 = Shape.class;

            print("c1------------------------------------------");
            printClz(c1);
            print("c2------------------------------------------");
            printClz(c2);
            print("c3------------------------------------------");
            printClz(c3);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void printClz(Class c) {
        print("名稱 " + c.getName());
        print("簡稱 " + c.getSimpleName());
        print("冠名 " + c.getCanonicalName());
        print("修飾符 " + Modifier.toString(c.getModifiers()));
        print("父類 " + c.getSuperclass());
        print("聲明類 " + c.getDeclaringClass());
        print("組件類型 " + c.getComponentType());
        print("關閉類 " + c.getEnclosingClass());
        for (Class clz : c.getInterfaces()) {
            print("接口 " + clz);
        }
        for (Annotation annotation : c.getAnnotations()) {
            print("註解(含繼承) " + annotation);
        }
        for (Annotation annotation : c.getDeclaredAnnotations()) {
            print("註解(當前) " + annotation);
        }
        for (Constructor constructor : c.getConstructors()) {
            print("構造函數(含繼承) " + constructor);
        }
        for (Constructor constructor : c.getDeclaredConstructors()) {
            print("構造函數(當前) " + constructor);
        }
        for (Method method : c.getMethods()) {
            print("方法(含繼承) " + method);
        }
        for (Method method : c.getDeclaredMethods()) {
            print("方法(當前) " + method);
        }
        for (Field field : c.getFields()) {
            print("參數(含繼承) " + field);
        }
        for (Field field : c.getDeclaredFields()) {
            print("參數(當前) " + field);
        }
    }
    private void print(String str) {
        Log.e("-s-", str);
        Log.e("-s-", "--------------------------------");
    }

結果如下

11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: c1------------------------------------------
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: 名稱 com.gjn.testproject.MainActivity$BaseClz
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: 簡稱 BaseClz
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: 冠名 com.gjn.testproject.MainActivity.BaseClz
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: 修飾符 abstract static
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: 父類 class java.lang.Object
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.544 22868-22868/com.gjn.testproject E/-s-: 聲明類 class com.gjn.testproject.MainActivity
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 組件類型 null
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 關閉類 class com.gjn.testproject.MainActivity
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 接口 interface com.gjn.testproject.MainActivity$InterFace
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 構造函數(當前) com.gjn.testproject.MainActivity$BaseClz()
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public void com.gjn.testproject.MainActivity$BaseClz.dos()
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public boolean java.lang.Object.equals(java.lang.Object)
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final java.lang.Class java.lang.Object.getClass()
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public int java.lang.Object.hashCode()
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.notify()
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.notifyAll()
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public java.lang.String java.lang.Object.toString()
11-12 14:37:57.545 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.wait() throws java.lang.InterruptedException
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final void java.lang.Object.wait(long) throws java.lang.InterruptedException
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 方法(當前) public void com.gjn.testproject.MainActivity$BaseClz.dos()
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 參數(含繼承) public com.gjn.testproject.MainActivity$Sex com.gjn.testproject.MainActivity$BaseClz.sex
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 參數(當前) protected java.lang.String com.gjn.testproject.MainActivity$BaseClz.base
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 參數(當前) private int com.gjn.testproject.MainActivity$BaseClz.n
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 參數(當前) public com.gjn.testproject.MainActivity$Sex com.gjn.testproject.MainActivity$BaseClz.sex
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: c2------------------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 名稱 com.gjn.testproject.MainActivity$Clz
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 簡稱 Clz
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 冠名 com.gjn.testproject.MainActivity.Clz
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 修飾符 static
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 父類 class com.gjn.testproject.MainActivity$BaseClz
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.546 22868-22868/com.gjn.testproject E/-s-: 聲明類 class com.gjn.testproject.MainActivity
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 組件類型 null
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 關閉類 class com.gjn.testproject.MainActivity
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 構造函數(當前) private com.gjn.testproject.MainActivity$Clz(java.lang.String)
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 構造函數(當前) com.gjn.testproject.MainActivity$Clz(java.lang.String,com.gjn.testproject.MainActivity$1)
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public void com.gjn.testproject.MainActivity$Clz.dos()
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public boolean java.lang.Object.equals(java.lang.Object)
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final java.lang.Class java.lang.Object.getClass()
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public int java.lang.Object.hashCode()
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.notify()
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.notifyAll()
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public java.lang.String java.lang.Object.toString()
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.547 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.wait() throws java.lang.InterruptedException
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final void java.lang.Object.wait(long) throws java.lang.InterruptedException
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 方法(當前) public void com.gjn.testproject.MainActivity$Clz.dos()
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 參數(含繼承) public java.lang.String com.gjn.testproject.MainActivity$Clz.str
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 參數(含繼承) public static java.lang.String com.gjn.testproject.MainActivity$Clz.STR
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 參數(含繼承) public com.gjn.testproject.MainActivity$Sex com.gjn.testproject.MainActivity$BaseClz.sex
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 參數(當前) private int com.gjn.testproject.MainActivity$Clz.num
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 參數(當前) public java.lang.String com.gjn.testproject.MainActivity$Clz.str
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 參數(當前) private static final int com.gjn.testproject.MainActivity$Clz.NUM
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 參數(當前) public static java.lang.String com.gjn.testproject.MainActivity$Clz.STR
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: c3------------------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 名稱 com.gjn.testproject.test.Shape
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.548 22868-22868/com.gjn.testproject E/-s-: 簡稱 Shape
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 冠名 com.gjn.testproject.test.Shape
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 修飾符 public
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 父類 class java.lang.Object
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 聲明類 null
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 組件類型 null
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 關閉類 null
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 接口 interface com.gjn.testproject.test.Draw
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 構造函數(含繼承) public com.gjn.testproject.test.Shape()
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 構造函數(含繼承) public com.gjn.testproject.test.Shape(java.lang.String)
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 構造函數(當前) public com.gjn.testproject.test.Shape()
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: 構造函數(當前) public com.gjn.testproject.test.Shape(java.lang.String)
11-12 14:37:57.549 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.550 22868-22868/com.gjn.testproject E/-s-: 構造函數(當前) private com.gjn.testproject.test.Shape(java.lang.String,java.lang.String)
11-12 14:37:57.550 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.550 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public void com.gjn.testproject.test.Shape.draw()
11-12 14:37:57.550 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.550 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public boolean java.lang.Object.equals(java.lang.Object)
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final java.lang.Class java.lang.Object.getClass()
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public java.lang.String com.gjn.testproject.test.Shape.getX()
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public int java.lang.Object.hashCode()
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.notify()
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.notifyAll()
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public void com.gjn.testproject.test.Shape.setX(java.lang.String)
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public java.lang.String java.lang.Object.toString()
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.wait() throws java.lang.InterruptedException
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final void java.lang.Object.wait(long) throws java.lang.InterruptedException
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(含繼承) public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: 方法(當前) private void com.gjn.testproject.test.Shape.xxx()
11-12 14:37:57.551 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 方法(當前) public void com.gjn.testproject.test.Shape.draw()
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 方法(當前) public java.lang.String com.gjn.testproject.test.Shape.getX()
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 方法(當前) public void com.gjn.testproject.test.Shape.setX(java.lang.String)
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(含繼承) public int com.gjn.testproject.test.Shape.num
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(含繼承) public java.lang.String com.gjn.testproject.test.Shape.s
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(含繼承) public static final java.lang.String com.gjn.testproject.test.Shape.SHAPE
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(當前) public int com.gjn.testproject.test.Shape.num
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(當前) public java.lang.String com.gjn.testproject.test.Shape.s
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(當前) private java.lang.String com.gjn.testproject.test.Shape.shape
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(當前) private java.lang.String com.gjn.testproject.test.Shape.x
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: 參數(當前) public static final java.lang.String com.gjn.testproject.test.Shape.SHAPE
11-12 14:37:57.552 22868-22868/com.gjn.testproject E/-s-: --------------------------------

Method

基本使用

正常我們都是獲取一個類的方法然後調用就好了,所以大多我們都不考慮繼承等方法。

  • Class.getDeclaredMethod(String name, Class<?>... parameterTypes) (其中Class是類)
  • Method.invoke(Object obj, Object... args)(其中Method是方法)

可以調用getDeclaredMethod獲取對應的Method(方法)然後用invoke來執行方法
注:如果想調用私有的方法需要調用setAccessible(boolean flag)強制打開權限,但是這個方法不一定能夠成功!

還是延用上面的代碼繼續寫如下

		try {
            ...//上面的c1 c2 c3 clz
            
            BaseClz baseClz = new BaseClz() {
                @Override
                public void dos() {
                    super.dos();
                }
            };
            Method m1 = c1.getDeclaredMethod("dos");
            m1.invoke(baseClz);

            Method m2 = c2.getDeclaredMethod("dos");
            m2.invoke(clz);

            Shape shape = new Shape("circle");
            Method m3 = c3.getDeclaredMethod("draw");
            m3.invoke(c3.newInstance());
            m3.invoke(shape);

            Method m4 = c3.getDeclaredMethod("xxx");
            m4.setAccessible(true);
            m4.invoke(c3.newInstance());
            m4.invoke(shape);

            Method m5 = c3.getDeclaredMethod("setX", String.class);
            m5.invoke(shape, "new x");
            Method m6 = c3.getDeclaredMethod("getX");
            print("getX = " + m6.invoke(shape));
        } catch (Exception e) {
            e.printStackTrace();
        }

結果如下

11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: BaseClz dos
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: Clz dos
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: draw null
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: draw circle
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: draw null
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: xxx => ?x?
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: draw circle
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: xxx => null
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: getX = new x
11-13 10:53:23.321 13278-13278/com.gjn.testproject E/-s-: --------------------------------

前面兩個m1和m2就是直接調用dos方法 按照測試類可以直接得出結果。


然後是m3這邊有兩個 一個是直接用類生成的對象c3.newInstance()還有一個是臨時創建的對象Shape shape = new Shape("circle");所以纔有了兩種結果


之後是m4我們可以看到去調用了私有的方法,就先取得權限在去調用方法


最後的m5 m6 就是對有參和有返回值的方法調用,其實和上面一樣只不過上面的方法沒有參數和返回值而已。

常見錯誤

  • 泛型擦除導致的 NoSuchMethodException

當你反射泛型的時候要記住泛型最後都被編譯成了Object!
例如

            Class c4 = new MethodT<Integer>().getClass();
            Method m7 = c4.getDeclaredMethod("t", Object.class);
            print(m7.toGenericString());
            Method m8 = c4.getDeclaredMethod("t", Integer.class);
            print(m8.toGenericString());

結果如下

11-13 11:39:19.851 15595-15595/com.gjn.testproject E/-s-: public void com.gjn.testproject.MainActivity$MethodT.t(T)
11-13 11:39:19.851 15595-15595/com.gjn.testproject E/-s-: --------------------------------
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err: java.lang.NoSuchMethodException: t [class java.lang.Integer]
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at java.lang.Class.getConstructorOrMethod(Class.java:472)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at java.lang.Class.getDeclaredMethod(Class.java:640)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at com.gjn.testproject.MainActivity.test(MainActivity.java:189)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at com.gjn.testproject.MainActivity.onCreate(MainActivity.java:95)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.app.Activity.performCreate(Activity.java:5248)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2164)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2249)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.app.ActivityThread.access$800(ActivityThread.java:141)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1212)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
11-13 11:39:19.851 15595-15595/com.gjn.testproject W/System.err:     at android.os.Looper.loop(Looper.java:136)
11-13 11:39:19.861 15595-15595/com.gjn.testproject W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5113)
11-13 11:39:19.861 15595-15595/com.gjn.testproject W/System.err:     at java.lang.reflect.Method.invokeNative(Native Method)
11-13 11:39:19.861 15595-15595/com.gjn.testproject W/System.err:     at java.lang.reflect.Method.invoke(Method.java:515)
11-13 11:39:19.861 15595-15595/com.gjn.testproject W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
11-13 11:39:19.861 15595-15595/com.gjn.testproject W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)
11-13 11:39:19.861 15595-15595/com.gjn.testproject W/System.err:     at dalvik.system.NativeStart.main(Native Method)
  • 訪問不可見方法導致的 IllegalAccessException

就是上面說的m4調用私用方法之前一定要先取得權限!setAccessible(true)

  • 反射調用方法時傳入錯誤參數導致的 IllegalArgumentException

如果參數傳多了或者少了會報這個錯誤!例如無參方法寫了參數或者有參方法沒寫參數。


Field

基本使用

和方法一樣我們大部分都只需要取當前類的值,所以我們調用getDeclaredField獲取成員變量

  • Class.getDeclaredField(String name)(其中Class是類)
  • Field.set(Object obj, Object value)(其中Field是成員變量)
  • Field.get(Object obj)(其中Field是成員變量)

例如如下

            Field f1 = c3.getDeclaredField("num");
            print("num = " + f1.get(shape));
            f1.set(shape, 7);
            print("num = " + f1.get(shape));

            Field f2 = c3.getDeclaredField("x");
            f2.setAccessible(true);
            print("x = " + f2.get(shape));
            f2.set(shape, "shape");
            print("x = " + f2.get(shape));

結果

11-13 17:08:15.222 29046-29046/com.gjn.testproject E/-s-: num = 0
11-13 17:08:15.222 29046-29046/com.gjn.testproject E/-s-: --------------------------------
11-13 17:08:15.222 29046-29046/com.gjn.testproject E/-s-: num = 7
11-13 17:08:15.222 29046-29046/com.gjn.testproject E/-s-: --------------------------------
11-13 17:08:15.223 29046-29046/com.gjn.testproject E/-s-: x = new x
11-13 17:08:15.223 29046-29046/com.gjn.testproject E/-s-: --------------------------------
11-13 17:08:15.223 29046-29046/com.gjn.testproject E/-s-: x = shape
11-13 17:08:15.223 29046-29046/com.gjn.testproject E/-s-: --------------------------------
11-13 17:08:15.223 29046-29046/com.gjn.testproject E/-s-: draw circle
11-13 17:08:15.223 29046-29046/com.gjn.testproject E/-s-: xxx => shape

調用私有的方法要注意也要setAccessible(true)獲取權限

常見錯誤

  • 無法轉換類型導致的 IllegalArgumentException
  • 反射非 public 的變量導致的 NoSuchFieldException
  • 修改 final類型的變量導致的 IllegalAccessException

總結

反射是會消耗資源的對運算也有性能開銷,因爲在反射時這樣的操作需要引發許多額外操作,比如驗證訪問權限等。


最好在比較特殊的情況使用,例如註解生成一系列的功能的時候。


而且編譯java代碼的時候編譯器是會對代碼進行優化的,好比你寫了String xx= "xxxxx"跟在後面又寫了xx="123"那麼代碼優化的時候會直接取後一個過濾掉多餘的代碼,但是使用反射成員變量的Field.set就沒有這些優化了。


還有一個要注意的就是,反射修改某些私有的成員變量的時候可能會導致部分變了部分沒變這類情況,所以要對反射的代碼邏輯很理解在使用比較好!



資料

深入理解 Java 反射:Class (反射的入口)
深入理解 Java 反射:Method (成員方法)
深入理解 Java 反射:Field (成員變量)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章