一、類的載入
當程式要使用某個類時,如果該類還未被載入到記憶體中,則系統會透過載入,連線,初始化三步來實現對這個類進行初始化
載入
就是將class檔案讀入記憶體,併為之建立一個Class物件
任何類被使用時系統都會建立一個Class物件
連線
驗證 是否有正確的內部結構,並和其他類協調一致
準備 負責為類的靜態成員分配記憶體,並設定預設初始化值
解析 將類的二進位制資料中的符號引用替換為直接引用
初始化
二、類初始化時機
建立類的例項
訪問類的靜態變數 ,或者為靜態變數賦值
呼叫類的靜態方法
使用反射方式來強制建立某個類或介面對應的java.lang.Class物件
初始化某個類的子類
直接使用java.exe命運來執行某個主類
三、類載入器
負責將.class檔案載入到記憶體中,併為之生成對應的Class物件。
雖然我們不需要關心類載入機制,但是瞭解這個機制我們就能更好的理解程式的執行。
類載入器的組成
Bootstrap ClassLoader 根類載入器
Extension ClassLoader 擴充套件類載入器
System ClassLoader 系統類載入器
四、反射
java反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;
對於任意一個物件,都能夠任意呼叫它的任意一個方法和屬性;
這種動態獲取的資訊以及動態調物件的方法的功能稱為java語言的反射機制。
想要解剖一個類,必須先要獲取到該類的位元組碼檔案物件。
而解剖使用的就是Class類中的方法。
所以先要獲取到每一個位元組碼檔案對應的Class型別的物件
五、透過反射獲取構造方法
類中的成員:
成員變數:Field
構造方法:Constructor
成員方法:Method
獲取類的Class物件
//方式1:在物件已經存在的前提下獲取
Student student = new Student("xiaohei",18,"anhui","nan");
Class<? extends Student> studentClass = student.getClass();
//方式2:透過類名.class的方式獲取 在同步鎖的場景下用的比較多
Class<Student> studentClass2 = Student.class;
System.out.println(studentClass2==studentClass);
//方式3:最常用的方式 利用Class類中的靜態方法
//static Class<?> forName(String className) 傳入的是類的路徑
Class<?> studentClass = Class.forName("com.shujia.day17.Student");
Constructor<T> getConstructor(Class<?>... parameterTypes) 只能某一個獲取公共的構造方法-
返回一個 Constructor物件,該物件反映 Constructor物件表示的類的指定的公共 類函式。
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 獲取某一個任意許可權修飾符的構造方法
Constructor<?>[] getDeclaredConstructors() 獲取所有的任意許可權修飾符的構造方法
使用獲取到的公共的構造方法
Constructor<?> constructor = studentClass.getConstructor(String.class, int.class, String.class, String.class);
T newInstance(Object... initargs)
Object o = constructor.newInstance("xxx", 18, "xxx", "男");
System.out.println(o);
使用獲取到的私有的構造方法建立物件
Constructor<?> declaredConstructor = studentClass.getDeclaredConstructor();
繞過許可權校驗,暴力訪問
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance();
System.out.println(o);
六、透過反射獲取成員變數並賦值
獲取類的位元組碼檔案物件
Class<?> studentClass = Class.forName("com.shujia.day17.Student");
Field getField(String name) 只能透過變數名獲取公共的成員變數----------------------------------------------
Field gender = studentClass.getField("gender");
System.out.println(gender);
Field[] getFields() 只能獲取所有公共的成員變數 ---------------------------------------------
Field[] fields = studentClass.getFields();
System.out.println(Arrays.toString(fields));
Field getDeclaredField(String name) 透過變數名獲取任意許可權修飾符的成員變數 ------------------------
Field name = studentClass.getDeclaredField("name");
System.out.println(name);
Field[] getDeclaredFields() 獲取所有成員變數 ---------------------------------------------
Field[] declaredFields = studentClass.getDeclaredFields();
System.out.println(Arrays.toString(declaredFields));
七、透過反射獲取成員方法並賦值
獲取類的位元組碼檔案物件
Class<?> studentClass = Class.forName("com.shujia.day17.Student");
Method getMethod(String name, Class<?>... parameterTypes) 只能獲取公共的成員方法,當前和父類的公共都可以----------------------
Method fun4 = studentClass.getMethod("fun4");
System.out.println(fun4);
Method fun5 = studentClass.getMethod("fun5", String.class);
System.out.println(fun5);
Method fun1 = studentClass.getMethod("wait");
System.out.println(fun1);
getMethods 獲取當前類及其父類中的所有公共的成員方法------------------------------------------
Method[] methods = studentClass.getMethods();
System.out.println(Arrays.toString(methods));
getDeclaredMethod() 獲取任意一個許可權修飾符的成員方法----------------------------------------
Method fun1 = studentClass.getDeclaredMethod("fun1");
System.out.println(fun1);
getDeclaredMethods 獲取當前類中的所有成員方法----------------------------------------
Method[] declaredMethods = studentClass.getDeclaredMethods();
System.out.println(Arrays.toString(declaredMethods));