反射(未完待續)

反射

反射機制(比較簡單,由於只要會查幫助文檔,就能夠了。)

反射的概述

  • 反射機制有什麼用?java

    • 經過java語言中的反射機制能夠操做字節碼文件。優勢相似於黑客。(能夠讀和修改字節碼文件。)經過反射機制能夠操做代碼片斷。(class文件。)
  • 反射機制的相關類在java.lang.reflect.*;包下。數組

  • 反射機制相關的重要的類有哪些?安全

    • java.lang.Class:表明整個字節碼,表明一個類型,表明整個類。工具

    • java.lang.reflect.Method:表明字節碼中的方法字節碼。表明類中的方法。測試

    • java.lang.reflect.Constructor:表明字節碼中的構造方法字節碼。表明類中的構造方法this

    • java.lang.reflect.Field:表明字節碼中的屬性字節碼。表明類中的成員變量(靜態變量+實例變量)。spa

    • java.lang.Class翻譯

      public class User{
      // 	Field
      	int no;
      
      // Constructor
      	public User(){
      				
      	}
      	public User(int no){
      		this.no = no;
      	}
      
      				// Method
      	public void setNo(int no){
      		this.no = no;
          }							
      	public int getNo(){
      		return no;
      	}
      }

```

獲取Class的三種方式

  • 要操做一個類的字節碼,須要首先獲取到這個類的字節碼,獲取java.lang.Class實例的三種方式。
    • 第一種方式:Class c = Class.forName("完整類名帶包名")
    • 第二種方式:Class c = 對象.getClass();
    • 第三種方式:Class c = 任何類型.class;
public class ReflectTest01 {
    public static void main(String[] args) {
        /*
        Class.forName()
            1.靜態方法
            2.方法的參數是一個字符串
            3.字符串須要的是一個完整的類名
            4.完整類名必須帶有包名。java.lang包也不能省。
         */
        Class c1 = null;
        Class c2 = null;
        try {
            c1 = Class.forName("java.lang.String");//c1表明String.class文件,或者說C1表明String類型
            c2 = Class.forName("java.util.Date");//c2表明Date類型
            Class c3 = Class.forName("java.lang.Integer");//c3表明Integer類型
            Class c4 = Class.forName("java.lang.System");//c4表明System類型
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
//        Java中任何一個對象都有一個方法:getClass()
        String s = "abc";
        Class x = s.getClass();//x表明String.class字節碼文件,x表明String類型
        System.out.println(c1 == x);//true (==判斷的是對象的內存地址)

        Date time = new Date();
        Class y = time.getClass();
        System.out.println(c2 == y);//true(c2和y兩個變量中保存的內存地址都是同樣的,都指向方法區中的字節碼文件)

//        第三種方式,Java語言中任何一種類型,包括基本數據類型,它都有.class屬性。
        Class z = String.class;//z表明String類型
        Class k = Date.class;//k表明Date類型
        Class f = int.class;//f表明int類型
        Class e = double.class;//e表明double類型
        System.out.println(x == z);//true
    }
}

經過反射實例化對象

  • 經過ClassnewInstance()方法來實例化對象
  • 注意:newInstance()方法內部實際上調用了無參數構造方法,必須保證無參構造存在才能夠。
  • 反射機制的靈活性,Java代碼寫一遍,在不改變Java源代碼的基礎上,能夠作到不一樣對象的實例化,很是靈活。(符合OCP開閉原則:對擴展開放,對修改關閉)
public class ReflectTest02 {
    public static void main(String[] args) {
//        這是不使用反射機制建立對象
        User user = new User();
        System.out.println(user);

//        下面這段代碼是以反射機制的方式建立對象。
        try {
//            經過反射機制,獲取Class,經過Class來實例化對象。
            Class c = Class.forName("com.yang.javaSE進階.反射.bean.User");//c表明User類型
//            newInstance()這個方法會調用User這個類的無參數構造方法,完成對象的建立
//            重點是:newInstance()調用的是無參構造,必須保證無參構造器是存在的
            Object obj = c.newInstance();
            System.out.println(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}
public class User {
    public User() {
        System.out.println("無參構造方法!");
    }
}

只讓靜態代碼塊執行

  • 記住(重點):若是隻是但願一個類的靜態代碼塊執行,其它代碼一概不執行。可使用:Class.forName("完整類名");這個方法的執行會致使類加載,類加載時,靜態代碼塊執行。
  • 提示:後面JDBC技術的時候咱們還須要.
public class ReflectTest03 {
    public static void main(String[] args) {
        try {
//            Class.forName()這個方法的執行會致使類加載
            Class.forName("com.yang.javaSE進階.反射.bean.MyClass");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
public class MyClass{
    //    靜態代碼塊在類加載時執行,而且只執行一次。
    static{
        System.out.println("MyClass類的靜態代碼塊執行了!");
    }
}

JDK中自帶的類加載器(不須要掌握,知道固然最好!)

  • 什麼是類加載器?專門負責加載類的命令/工具。ClassLoader
  • JDK中自帶了3個類加載器
    • 啓動類加載器:rt.jar
    • 擴展類加載器:ext/*.jar
    • 應用類加載器:classpath
  • 假設有這樣一段代碼:String s = "abc";
    • 代碼在開始執行以前,會將所須要類所有加載到JVM當中。經過類加載器加載,看到以上代碼類加載器會找String.class文件,找到就加載,那麼是怎麼進行加載的呢?
      • 首先經過「啓動類加載器」加載。注意:啓動類加載器專門加載:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jarrt.jar中都是JDK最核心的類庫。
      • 若是經過「啓動類加載器」加載不到的時候,會經過"擴展類加載器"加載。注意:擴展類加載器專門加載:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar
      • 若是「擴展類加載器」沒有加載到,那麼會經過「應用類加載器」加載。注意:應用類加載器專門加載:classpath中的類。
  • java中爲了保證類加載的安全,使用了雙親委派機制。優先從啓動類加載器中加載,這個稱爲「父」,「父」沒法加載到,再從擴展類加載器中加載,這個稱爲「母」。雙親委派。若是都加載不到,纔會考慮從應用類加載器中加載。直到加載到爲止。

獲取反射屬性Field

  • 反射Field類中全部的Field
public class ReflectTest04 {
    public static void main(String[] args) throws Exception {
//        獲取整個類
        Class studentClass = Class.forName("com.yang.javaSE進階.反射.bean.Student");
//        獲取類中全部的Field
        Field[] fields = studentClass.getFields();
        System.out.println(fields.length);//測試數組中只有一個元素
//        取出這個Field
        Field f = fields[0];
//        取出這個Field的名字
        String fieldName = f.getName();
        System.out.println(fieldName);
//        獲取全部的Field
        Field[] fs = studentClass.getDeclaredFields();
        System.out.println(fs.length);
//        遍歷
        for (Field field : fs) {
//            獲取屬性的修飾符
            int i = field.getModifiers();//返回的修飾符是一個數字,每一個數字是修飾符的代號!
            System.out.println(i);
//            能夠將這個「代號」數字轉換成「字符串」
            String modifierString = Modifier.toString(i);
            System.out.println(modifierString);
            //            獲取屬性的類型
            Class fieldType = field.getType();
//            String fName = fieldType.getName();
            String fName = fieldType.getSimpleName();
            System.out.println(fName);
//            獲取屬性的名字
            System.out.println(field.getName());
        }
    }
}
public class Student {
    //    Field翻譯爲字段,其實就是屬性/成員
//    4個Field,分別使用了不一樣的訪問控制權限修飾符
    public int no;
    private String name;
    protected int age;
    boolean sex;
    public static final double MATH_PI = 3.1415926;
}

反編譯Field

相關文章
相關標籤/搜索