Java反射

Java反射

\color{red}{GitHub連接}

1.Class 類

  • 類是對象,類是java.lang.Class類的實例對象java

    public class MyClass {
        public static void main(String[] args) {
            // People的實例對象
            People people = new People();
            // 任何一個類,都是java.lang.Class的實例對象
        }
    }
    // People自己就是一個對象,是java.lang.Class的對象
    class People { }
    複製代碼
  • Class類的三種表達方式android

    Class c1 = People.class;
    // 方法2:經過已知類對象的getClass方法
    Class c2 = people.getClass();
    // 方法3:經過Class類靜態方法forName()
    Class c3 = Class.forName("com.nj.reflect.People");
    
    /* * c一、c2表示了People類的類類型(class type) * 類也是對象,是Class類的實例對象,這個對象咱們稱爲該類的類類型 */
    // 無論是c一、c2仍是c3都表明People的類類型,一個類只多是Class類的一個實例對象。
    System.out.print(c1 == c2); // true
    System.out.print(c1 == c3); // true
    複製代碼
  • 獲取對象實例git

    // 經過People類的類類型c一、c2或c3建立該類的實例對象。
    People people1 = (People) c1.newInstance(); // 須要有無參構造方法
    複製代碼

2.動態加載類

  • Class.forName("類的全稱")github

    • 不只表示了類的類類型,還表明了動態加載類
    • 編譯時刻加載類是靜態加載類,運行時刻加載類是動態加載類。
  • 靜態加載類數組

    public class Animal {
        public static void main(String[] args) {
            if (args[0].equals("Dog")) {
                Dog dog = new Dog();
                dog.eat();
            }
            if (args[0].equals("Cat")) {
                Cat cat = new Cat();
                cat.eat();
            }
        }
    }
    class Dog {
        public void eat() { }
    }
    class Cat {
        public void eat() { }
    }
    複製代碼
    • 靜態加載類的缺點ide

      1.若是Dog或者Cat不存在,會報錯。可是Dog和Cat不必定會使用。函數

      2.經過new建立對象是靜態加載類,在編譯時刻,就須要加載全部可能使用到的類。spa

  • 動態加載類code

    經過Class.forName()動態加載類,就不會在編譯時報錯了。對象

    public class AnimalManager {
        public static void main(String[] args){
            try {
                // 動態加載類,在運行時刻加載。編譯不會再報錯。
                Class c = Class.forName(args[0]);
                // 建立對象,經過類類型建立該類的對象
                Object o = c.newInstance();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    複製代碼

    可是咱們經過c.newInstance()建立類對象的時候,問題來了,是該轉換成Dog,仍是該轉換成Cat。因此,須要統一標準,建立Animals接口,使Dog和Cat都實現Animals接口。

    public class AnimalManager {
        public static void main(String[] args){
            try {
                // 動態加載類,在運行時刻加載。編譯不會再報錯。
                Class c = Class.forName(args[0]);
                // 建立對象,經過類類型建立該類的對象
                Animals animals = (Animals) c.newInstance();
                animals.eat();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    interface Animals{
        void eat();
    }
    class Dog implements Animals{
        @Override
        public void eat() {}
    }
    class Cat implements Animals{
        @Override
        public void eat() {}
    }
    複製代碼
    • 優勢

      1.動態加載,更加靈活

      2.方便拓展,若是想要加個Pig類,直接建立Pig類,實現Animals接口和方法便可,無需再修改AnimalManager類。

3.反射的使用

  • 獲取class對象的相關信息

    1.獲取class對象的成員變量

    // 獲取class1對象的全部成員變量,不包括父類的成員變量
    Field[] allFields = class1.getDeclaredFields();
    // 獲取class1對象的public成員變量,包括父類裏面的成員變量
    Field[] publicFields = class1.getFields();
    // 獲取class1對象指定的成員變量,父類的沒法獲取
    Field name1 = class1.getDeclaredField("name");
    // 獲取class1對象指定的public成員變量,包括查找父類
    Field name2 = class1.getField("name");
    
    // 獲取變量的名稱
    String name = field.getName();
    // 獲取變量的類型
    Class type = field.getType();
    複製代碼

    2.獲取class對象的方法

    // 獲取class1對象的全部方法,不包括父類的方法
    Method[] allMethods = class1.getDeclaredMethods();
    // 獲取class1對象的public方法,包括父類的public方法
    Method[] publicMethods = class1.getMethods();
    // 獲取class1對象指定的方法,父類的沒法獲取
    Method method1 = class1.getDeclaredMethod("getName");
    // 獲取class1對象指定的方法,而且有一個int類型參數的方法
    Method method2 = class1.getDeclaredMethod("getName", int.class);
    // 獲取class1對象有兩個參數的指定方法
    Method method3 = class1.getDeclaredMethod("getName", int.class, String.class);
    // 獲取class1對象指定的public方法,包括父類的public方法。
    Method method4 = class1.getMethod("getName");
    複製代碼

    3.獲取class對象的構造函數

    // 獲取class1對象全部的構造函數
    Constructor[] allConstructors = class1.getDeclaredConstructors();
    // 獲取class1對象public的構造函數
    Constructor[] publicConstructors = class1.getConstructors();
    // 獲取class1對象指定參數的構造函數
    Constructor constructor1 = class1.getDeclaredConstructor(int.class);
    // 獲取class1對象指定參數而且爲public的構造函數
    Constructor constructor2 = class1.getConstructor(int.class, String.class);
    複製代碼

    4.class對象的其餘方法

    Annotation[] annotations = class1.getAnnotations();// 獲取class對象的全部註解
    Annotation annotation = class1.getAnnotation(Override.class);// 獲取class對象指定註解
    Class superclass = class1.getSuperclass(); // 獲取class對象直接父類的類對象
    Type genericSuperclass = class1.getGenericSuperclass(); // 獲取class對象的直接父類的Type
    Type[] genericInterfaces = class1.getGenericInterfaces(); // 獲取class對象全部接口的Type集合
    String name = class1.getName(); // 獲取class對象名稱,包括報名路徑
    String simpleName = class1.getSimpleName(); // 獲取class類名
    Package aPackage = class1.getPackage(); // 獲取class包信息
    boolean annotation = class1.isAnnotation();// 判斷是否爲註解類
    boolean anEnum = class1.isEnum();// 判斷是否爲枚舉
    boolean anInterface = class1.isInterface();// 判斷是否爲接口類
    boolean array = class1.isArray();//判斷是否爲集合類型
    boolean primitive = class1.isPrimitive(); // 判斷是否爲原始類型(8個基礎類型)
    boolean anonymousClass = class1.isAnonymousClass(); // 判斷是不是匿名內部類
    boolean annotation1 = class1.isAnnotationPresent(Override.class);//判斷是否被某個註解類修飾
    複製代碼

    5.Method的相關方法

    Method method = class1.getMethod("getName", String.class);
    String name = method.getName(); // 獲取方法名稱
    // 獲取方法的返回值類型的類類型
    Class returnType = method.getReturnType();
    // 獲取方法的參數列表類型的類類型的數組
    Class[] parameterTypes = method.getParameterTypes();
    複製代碼
  • Java反射的使用

    1.生成來的實例對象

    // 方法一:調用newInstance()方法,可是這個方法要求class1的類必須有無參構造函數。
    Dog dog = (Dog) class1.newInstance();
    // 方法二:經過getConstructor獲取有參的Constructor構造函數,再調用newInstance()建立實例
    Constructor constructor = class1.getConstructor(String.class);
    Dog dog1 = (Dog) constructor.newInstance("dog");
    複製代碼

    2.調用類的方法

    // 第一步:生成類對象
    Dog dog = (Dog) class1.newInstance();
    // 第二步:經過class對象的getMethod()等方法,得到具體須要執行的Method對象。
    Method method = class1.getDeclaredMethod("getName", String.class);
    // 若是方法是private修飾,直接調用invoke,會報錯,Java要求程序必須有調用該方法的權限。
    // 調用setAccessible,並將參數設置爲true,就會取消Java語言的訪問權限檢查。
    method.setAccessible(true);
    // 調用Method對象的invoke方法,第一個參數是調用該方法的實例對象,第二個參數是對應須要傳入的參數。
    // invoke的返回值:若是方法的返回值爲void,則invoke返回null,若是不是void,則返回具體的返回值
    // 至關於 dog.getName("dog");
    Object o = method.invoke(dog, "dog");
    複製代碼

    3.訪問成員變量的值

    // 第一步:生成類對象
    Dog dog = (Dog) class1.newInstance();
    // 第二步:經過getDeclaredField等方法,獲取相應的Field對象
    Field field = class1.getDeclaredField("age");
    // 取消Java權限檢查
    field.setAccessible(true);
    // 獲取dog對象中age成員變量的值
    int age = field.getInt(dog);
    // 修改dog對象中age成員變量的值
    field.setInt(dog, 25);
    // 獲取dog對象中String類型的成員變量
    Field field1 = class1.getDeclaredField("name");
    // 取消Java權限檢查
    field1.setAccessible(true);
    // 獲取name變量的值
    Object o = field1.get(dog);
    // 修改name變量的值
    field1.set(dog, "sam");
    複製代碼

參考資料

1.Java反射

相關文章
相關標籤/搜索