【Java 反射學習】Java 反射基礎

知識點

類是用來描述對象的,而反射就能夠理解爲是用來描述類的。java

類中的屬性包括:app

  • Class 類自己
  • Package 類所在的包
  • Field 類中的屬性
  • Method 類中的方法
  • Constructor 類中的構造方法
  • Annotation 類中的註解

如何獲取Class

1.Class的靜態方法,forName("全類名")工具

2.類.class關鍵字測試

3.對象引用.getClass()方法 Object中的方法ui

Class中的經常使用方法

/*
0--默認不寫 1--public 2--private 4--protected 8--static 16--final 32--synchronized 64--volatile 128--transient 256--native 512--interface 1024--abstract
*/
int = getModifiers();		//獲取類的修飾符(權限+特徵)
String = getName();			//獲取類的全類名
String = getSimpleName();	 //獲取簡單名(只有類名 )
Class = getSuperClass();	 //獲取當前父類的對應Class
Class[] = getInterfaces();	 //獲取當前父類的接口
Package p = getPackage();	 //獲取當前類所在的包
		p.getName();		//獲取包的名字
Class[] = getClasses();		 //獲取類中的內部類

Object = newInstance();		//獲取當前類的對象(至關於調用了類中的無參數的構造方法)若是類中不存在無參數的構造方法,就會拋出NoSuchMethodException異常
Field = getField("屬性名");		  //獲取類中的屬性(公有的 本身類+父類)
Field[] = getFields();				//獲取類中的所有屬性(公有的 本身類+父類)
Field = getDeclaredField("屬性名")	   //獲取當前類的屬性(公有 + 私有 本身類)
Field = getDeclaredFields()	   //獲取當前類的所有屬性(公有 + 私有 本身類)
    若是想修改私有的屬性則須要設置屬性能夠被操做
    	setAccessible()
public class TestMain {
    public static void main(String[] args) {

        try {
            Class<?> clazz = Class.forName("com.lili.reflect.People");
            Package aPackage = clazz.getPackage();
            int modifiers = clazz.getModifiers();
            System.out.println(modifiers);
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                System.out.println(method.getName());
            }
            System.out.println(aPackage);

            Class<?>[] interfaces = clazz.getInterfaces();
            for (Class c : interfaces) {
                System.out.println(c.getName());
            }

            ArrayList<String> list = new ArrayList<>();
            Class c = ArrayList.class;
            Class superclass = c.getSuperclass();
            while (superclass != null) {
                System.out.println(superclass.getName());
                superclass = superclass.getSuperclass();
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

利用反射修改String類型的值

/*
注意只能是繞過private去修改屬性的值,而不能去修改屬性的長度,由於是final修飾的。
String的不可變指的是長度+值的不可變
*/
public class ChangeString {

    public static void main(String[] args) {

        try {
            String str = new String("abc");
            System.out.println(str);

            //一、利用反射技術獲取String的Class
            Class clazz = str.getClass();
            //二、獲取屬性
            Field f = clazz.getDeclaredField("value");
            //三、設置能夠修改屬性的值
            f.setAccessible(true);
            //四、獲取屬性的值
            char[] newChar = (char[])f.get(str);
            //五、修改屬性的值
            newChar[0] = 'xu';
            newChar[1] = 'Li';
            newChar[2] = 'Li';
            System.out.println(str);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

}

利用反射調用類中的方法

能夠獲取共有的方法,包括本身類的以及父類的spa

能夠找到私有的方法,可是要經過setAccessible(true)方法來執行私有的方法。設計

/**
 * 測試使用反射獲取類中的方法
 */
public class TestMethod {

    public static void main(String[] args) {
        try {
            //一、獲取People類對應的Class
            Class clazz = People.class;
            //二、獲取對象
            People p = (People) clazz.newInstance();
            //三、經過clazz獲取其中的方法,經過方法名以及方法的參數類型來定位方法。
            Method m = clazz.getMethod("eat", String.class);
            //四、調用方法,第一個參數是要執行方法的對象,第二個則是傳進去的參數列表
            String n = (String) m.invoke(p, "lili要開始吃飯啦");
            System.out.println(n);

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

利用反射執行構造方法

/**
 * 利用反射執行構造方法
 */
public class TestConstructor {
    public static void main(String[] args) {
        try {
            //一、獲取People對應的Class
            Class<People> clazz = People.class;
            //二、獲取People中的構造方法,其中省去了構造方法的名稱,由於是與類同名
            //無參的就是調用的無參數的構造方法
            //有參數的就是傳的構造方法中形參的類型.class
            Constructor<People> constructor = clazz.getConstructor(String.class);
            //三、執行構造方法,同理參數就是要傳參數的實參
            People people = constructor.newInstance("哈哈哈哈哈");
            System.out.println(people);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

設計一個小工具

這個小工具能夠代替咱們本身建立對象的功能,經過傳遞一個字符串,來幫咱們建立一個對象,同時還能將對象內的全部屬性賦值。code

其實這就是簡單的模擬了Spring中IOC思想的原理,IOC(Inversion Of Control)控制反轉:將對象的控制權反轉,交給Spring容器去處理;DI(Dependency Injection)依賴注入:Spring容器建立對象的同時幫咱們自動的注入屬性的值。對象

public class MySpring {
    //設計一個方法,將咱們建立對象的過程交給該方法去執行。
    //參數String類型的全類名
    //返回值 建立出來的對象 Object類型--->再添加上DI依賴注入
    public Object getBean(String classPath) {
        Object obj = null;
        //模擬輸入的實參
        Scanner scanner = new Scanner(System.in);
        System.out.println("請給"+ classPath +"的屬性賦值");
        try {
            //一、獲取該路徑下對應的Class
            Class clazz = Class.forName(classPath);
            //二、建立一個對象
            obj = clazz.newInstance();
            //使用set方法對對象的屬性進行賦值,找到每個不一樣對象對應的set方法。
            //也就是字符串set+屬性的名字
            //三、獲取類中的屬性
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                //獲取屬性的名稱
                String fieldName = field.getName();
                //改變屬性名中第一個字母的大小寫
                String first = fieldName.substring(0, 1).toUpperCase();
                //獲取屬性名中除開第一個字母的字段
                String last = fieldName.substring(1);
                //拼接set方法
                StringBuilder methodName = new StringBuilder("set");
                methodName.append(first);
                methodName.append(last);
                //四、獲取屬性的類型
                Class fieldType = field.getType();
                //五、獲取方法
                Method method = clazz.getMethod(methodName.toString(), fieldType);
                //接收實參
                System.out.println("請給"+ fieldName +"屬性賦值");
                String value = scanner.nextLine();
                /*爲了解決參數類型不一致的問題,能夠將參數的類型都設置未相應的包裝類,
                而且將它們都轉換成String的類型,除了Char類型以外須要另外的判斷。
                能夠利用其它包裝類帶String類型的構造方法進行處理。
                */
                Constructor con = fieldType.getConstructor(String.class);


                //六、執行方法
                method.invoke(obj, con.newInstance(value));

            }


        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}
相關文章
相關標籤/搜索