探索基礎之反射——第一章

半杯態發表於2020-10-24

小白的成長來源於努力學習,堅持每天的積累。 ——半杯態

一、獲取Class型別;

1.型別名.class

這種方式:簡潔,但是編譯期才可以使用。

  public void test01() {
        Class B1 = int.class;  //基本資料型別

        Class<Void> voidClass = void.class; // 特殊的空型別

        Class<String> stringClass = String.class;  //jdk 定義的型別

        Class<Serializable> serializableClass = Serializable.class;  //獲取介面型別

        Class<int[]> arryList = int[].class;  // 獲取陣列型別

        Class<TestClass> testClassClass = TestClass.class;  //自定義型別

        Class<ElementType> elementTypeClass = ElementType.class;  //列舉型別

        System.out.println(elementTypeClass);
    }

2.物件.getClass()

這個方法在java.lang.Object型別中宣告的,返回物件的執行時型別

   @Test
    public void test02() {
        Class c2 = String.class;
        //重點在student
        Student student = new Student();
        student.getClass();
        Class c1 = "".getClass();
        Class<Student> studentClass = Student.class;
        System.out.println(studentClass);
        System.out.println(c1 == c2);
    }

3.Class.forName(“型別全名稱”)

這個型別可以在編譯期間未知,這個類名稱可以在程式碼中出現,也可以配置在配置檔案中,或者鍵盤輸入等方式來指定。

  @Test
    public void test03() throws ClassNotFoundException {

        Class<?> name = Class.forName("com.banbeitai.reflect.Student");

        System.out.println(name);
    }

4.使用類載入器物件.loadClass(“型別全名稱”)

一般都是用在自定義類載入器物件去載入指定路徑下的類

  @Test
    public void test04() throws ClassNotFoundException {
        Class<TestClass> testClassClass = TestClass.class;
        ClassLoader classLoader = testClassClass.getClassLoader();

        Class<?> loadClass = classLoader.loadClass("com.banbeitai.reflect.Student");

        System.out.println(loadClass);

    }

二、反射的作用與運用

1、在執行時能夠獲取任意型別的詳細資訊
2、在執行時能夠建立任意引用資料型別的物件
3、在執行時可以為任意物件的任意屬性賦值,或者獲取任意物件的任意屬性的值
4、在執行時可以呼叫任意物件的任意方法

5、在執行時讀取某個註解資訊

6、在執行時讀取某個類的泛型實參

使用步驟:

(1)獲取這個類的Class物件

(2)獲取類的資訊

①包名②類名③類的修飾符Modifier④直接父類⑤父介面⑥屬性⑦構造器⑧方法

package com.banbeitai.reflect;

import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.Properties;

public class TestClassInfo {
    private Class clazz;

    @Before
    public void loadClass() throws IOException, ClassNotFoundException {
        Properties pro = new Properties();
        pro.load(TestClassInfo.class.getResourceAsStream("bean.properties"));
        String className = pro.getProperty("className");
        clazz = Class.forName(className);
        System.out.println(className);
    }

    @Test
    public void getProperty() {

        //獲取類所在的包名
        Package aPackage = clazz.getPackage();
        System.out.println("獲取包名:" + aPackage);
        //獲取類名
        System.out.println("獲取包名:" + clazz.getName());
        //獲取類的修飾符
        int mod = clazz.getModifiers();
        System.out.println("修飾符的值:" + mod);
        System.out.println("修飾符:" + Modifier.toString(mod));
        //獲取類的父類
        System.out.println("父類是:" + clazz.getSuperclass());
        //返回該類實現和繼承的介面
        Class[] interfaces = clazz.getInterfaces();
        for (Class inter : interfaces) {
            System.out.println(inter.getName());
        }
        //每一個屬性就是一個Field的物件
        /*
         * (1)Field[] getFields() 得到所有公共的屬性   包含本類非私有修飾的以及父級(介面,類)的全部的成員變數
         * (2)Field[] getDeclaredFields() 得到所有宣告的屬性
         */
        Field[] fields = clazz.getFields();
        //Field[] fields = clazz.getDeclaredFields();
        int count = 0;

        for (Field field : fields) {
            count++;
            int fMod = field.getModifiers();
            System.out.println("序號:" + count + ":屬性名:" + field.getName());
            System.out.println("序號:" + count + ":屬性的資料型別:" + field.getType().getName());
            System.out.println("序號:" + count + ":屬性的修飾符::" + Modifier.toString(fMod));
        }

        /*
         * Constructor[]  getConstructors():得到所有的公共的構造器
         * Constructor[]  getDeclaredConstructors()():得到所有的宣告的構造器
         */
        count = 0;
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("序號:" + count + ":構造器名字:" + constructor.getName());
            int cMod = constructor.getModifiers();
            System.out.println("序號:" + count + ":構造器修飾符:" + Modifier.toString(cMod));

            Class[] parameterTypes = constructor.getParameterTypes();
            Parameter[] parameters = constructor.getParameters();
            for (Parameter parameter : parameters) {
                System.out.println(parameter.toString());
            }

            System.out.println(count + ":構造器的形參列表:" + Arrays.toString(parameterTypes));


            /* (1)Method[] getMethods(); 得到所有公共的方法
             * (2)Method[] getDeclaredMethods(); 得到所有宣告的方法
             */
        }

        /* (1)Method[] getMethods(); 得到所有公共的方法
         * (2)Method[] getDeclaredMethods(); 得到所有宣告的方法
         */
        count=0;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            count++;
            int mMod = method.getModifiers();
            System.out.println(count + ":方法的修飾符:" + Modifier.toString(mMod));
            System.out.println(count +":方法的返回值型別:" + method.getReturnType());
            System.out.println(count + ":方法的名稱:" + method.getName());
            System.out.print(count + ":丟擲的異常型別們:");
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            System.out.println(Arrays.toString(exceptionTypes));
            Class[] parameterTypes = method.getParameterTypes();
            System.out.println(count + ":方法的形參列表:" + Arrays.toString(parameterTypes));
        }
    }
}

2.1 建立物件

方式一:使用Class物件直接new物件

方式二:使用構造器建立物件

package com.banbeitai.reflect.Demo2;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;

public class TestNewInstance {

    //使用反射建立物件
    @Test
    public void createObject() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        Class<?> forName = Class.forName("com.banbeitai.reflect.demo1.Student");

        //通過Class類建立物件
        Object instance = forName.newInstance();
        System.out.println(instance);
        System.out.println("--------通過構造器建立物件---------");
        Constructor<?> constructor = forName.getConstructor();
        Object newInstance = constructor.newInstance();
        System.out.println(newInstance);
        System.out.println("--------通過有參構造器建立物件---------");

        Constructor<?> nameConstructor = forName.getConstructor(String.class, LocalDate.class);
        Object paramConstructor  = nameConstructor.newInstance("小米", LocalDate.now());
        System.out.println(paramConstructor);

        System.out.println("---------------獲取私有構造器---------------------");
        Constructor<?> privateonstructor = forName.getDeclaredConstructor(String.class);

        //開啟獲取私有修飾內容的許可權
        privateonstructor.setAccessible(true);

        Object privateObj = privateonstructor.newInstance("小軍");
        System.out.println(privateObj);

    }
}

2.2 為物件的屬性賦值,以及獲取對應屬性的值

方法含義/解釋
set(Object obj, Object value)為成員屬性設定值,引數介紹:第一個引數是物件,第二引數是屬性的值(Field)
Object get(Object obj)獲取某個屬性的值,引數介紹:物件
setAccessible(true)開啟訪問許可權,true為可以訪問
package com.banbeitai.reflect.Demo2;

import org.junit.Test;

import java.lang.reflect.Field;
import java.time.LocalDate;

public class TestField {

    @Test
    public void getField() {
        //(1)獲取某個型別的Class物件
        try {
            Class clazz = Class.forName("com.banbeitai.reflect.demo1.Student");
            Object newInstance = clazz.newInstance();

            Field field = clazz.getDeclaredField("name");
            Field localDate = clazz.getDeclaredField("localDate");
            localDate.setAccessible(true);
            field.setAccessible(true);
            field.set(newInstance, "小軍");
            localDate.set(newInstance, LocalDate.now());

            System.out.println(newInstance);

            Object obj = field.get(newInstance);

            System.out.println(obj);
            System.out.println(localDate.get(newInstance));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.3 得到所有公共的方法/私有方法 Method類

package com.banbeitai.reflect.Demo3;

import java.lang.reflect.Method;

public class TestFastMethod {

    public static void main(String[] args) throws Exception {

        //(1)獲取Class物件:四種方式之一
        Class clazz = Class.forName("com.banbeitai.reflect.demo1.Student");

        //(2)得到方法Method物件
        //例如:得到void setInfo(String info)方法
        /*
         * (1)Method clazz.getMethod(name, parameterTypes):得到公共的方法
         * (2)Method clazz.getDeclaredMethod(name, parameterTypes):得到宣告的方法
         * 一個類中方法是可能過載,如何定位到某一個方法    方法名 + 形參列表
         */
        Method method = clazz.getDeclaredMethod("getInfo", String.class);

        //(3)呼叫方法
        /*
         * 靜態方法:
         * 		類名.方法(【實參列表】)
         * 非靜態方法
         * 		物件名.方法(【實參列表】)
         */
        //建立物件
        Object obj = clazz.newInstance();
        //呼叫方法
        method.invoke(obj, "半杯態");
        System.out.println(obj);
        //獲取public static void

        Method testMethod = clazz.getDeclaredMethod("test", int.class);
        //呼叫方法
        testMethod.invoke(null, 10);
    }

}

相關文章