类加载、类加载器、反射
1. 類加載
若程序使用的類未加載到內存中,則系統會通過加載、連接、初始化三步實現對這個類的加載。
1.1 加載
將class文件讀入內存,并為之建立一個Class對象
任何類被使用時都會有一個Class對象。
1.2 連接
1.2.1 驗證
是否有準確的內部結構,并和其他類協調一致
1.2.2 準備
負責為類的靜態成員分配內存,并設置默認初始化
1.2.3 解析
將類的二進制數據中的符號引用替換為直接引用。
1.3 初始化
1.3.1 類的初始化時機
- 創建類的實例
- 類的靜態變量,或者為靜態變量賦值
- 類的靜態方法
- 使用反射方法強制創建某個類或接口對應的java.lang.Class對象
- 初始化某個類的子類
- 直接使用java.exe命令來運行某個主類
2. 類加載器
負責將.class文件加載到內存中,并為之生成對應的Class對象。
組成:
2.1 Bootstrap ClassLoader
根類加載器,負責Java核心類的加載。
在JDK中JRE的lid目錄下的rt.jar文件中。
2.2 Extension ClassLoader
擴展類加載器
負責JRE的擴展目錄中jar包的加載。
在JDK中JRE的lib目錄下ext目錄
2.3 System ClassLoader
系統類加載器
負責在JVM啟動時加載在java命令的class文件,以及classpath環境變量所指定的jar包和類路徑。
3. 反射
概覽:
每個類都有一個 Class 對象,包含了與類有關的信息。
當編譯一個新類時,會產生一個同名的 .class 文件,該文件內容保存著 Class 對象。
類加載相當于 Class 對象的加載。類在第一次使用時才動態加載到 JVM 中,可以使用 Class.forName("com.mysql.jdbc.Driver") 這種方式來控制類的加載,該方法會返回一個 Class 對象。
反射可以提供運行時的類信息,并且這個類可以在運行時才加載進來,甚至在編譯時期該類的 .class 不存在也可以加載進來。
Class 和 java.lang.reflect 一起對反射提供了支持,java.lang.reflect 類庫主要包含了以下三個類:
- Field :可以使用 get() 和 set() 方法讀取和修改 Field 對象關聯的字段;
- Method :可以使用 invoke() 方法調用與 Method 對象關聯的方法;
- Constructor :可以用 Constructor 創建新的對象。
Java反射機制是在運行狀態中。
對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能調用它的任意一個方法和屬性。這種動態獲取的信息以及動態調用對象的方法的功能稱為Java語言的反射機制
3.1 Class類
Class類的實例表示正在運行的 Java 應用程序中的類和接口.
- 枚舉是一種類,注釋是一種接口。
- 每個數組屬于被映射為Class對象的一個類,所有具有相同元素類型和維數的數組都共享該Class對象。
- 基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也表示為Class對象。
沒有公共構造方法
Class對象是在加載類時由JVM通過調用類加載器中的defineClass()方法自動創建的。
使用Class對象來顯示對象的類名:
void printClassName(Object obj) {System.out.println("The class of " + obj +" is " + obj.getClass().getName()); }獲取Class對象的3種方式:
1、Object類中的getObject()方法:
Person p=new Person(); Class c=p.getObject();2、由類名.class獲取到字節碼文件對象(任意數據類型都有一個class靜態屬性)
Class c1=Person.class;3、由Class類方法(將類名作為字符串傳給Class類中的靜態方法forName())
Class c3=Class.forName("Person");總結:
1、2必須明確Person類型
3指定這種類型的字符串,擴展更強,不需知道類,只需提供字符串,按照配置文件加載即可。
使用3需在方發出聲明throws ClassNotFoundException
3.2 通過反射獲取構造方法并使用
在反射機制中,把類的成員(構造方法、成員方法、成員變量)都封裝成了對應的類進行表示。其中構造方法用Constructor類表示。
3.2.1 Constructor類
java.reflect.Constructor;
它提供關于類的單個構造方法的信息以及對它的訪問權限。
方法:
T newInstance(Object...initargs):使用此Constructor對象表示的構造方法來創建該構造方法的聲明類的新實例,并用指定的初始化參數初始化該實例。
可用Class類中提供的方法獲取構造函數。
public Constructor<T> getConstructor(Class<?>... parameterTypes):返回一個Constructor對象,它反映此Class對象所表示的類的指定公共構造方法。
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回一個Constructor對象,該對象反映此Class對象所表示的類或接口的指定構造方法。
public Constructor<T>[ ]? getConstructors():返回一個包含某些Constructor對象的數組,這些對象反映此Class對象所表示的類的所有公共構造方法。
public Constructor<T>[ ] getDeclaredConstructors():返回Constructor對象的一個數組,這些對象反映此Class對象表示的類聲明的所有構造方法。
需加:NoSuchMethodExceotion、SecurityException
Constructor cons=c.getConstructor(String.class);- 若用getConstructors(Class<?>... parameterTypes)獲取private,會有——java.lang.NoSuchMethodException
- 若用getDeclaredConstructor()獲取public方法,無提示,可正常運行,因為這個方法可獲取所有構造方法
3.3 通過反射獲取構造方法并創建對象
步驟:
3.4 使用反射獲取私有構造方法,創建對象
3.4.1 AccessibleObject類
直接已知子類:
Constructor, Field, Method
它提供了將反射的對象標記為在使用時取消默認 Java 語言訪問控制檢查的能力。
- 對于公共成員、默認(打包)訪問成員、受保護成員和私有成員,在分別使用 Field、Method 或 Constructor 對象來設置或獲取字段、調用方法,或者創建和初始化類的新實例的時候,會執行訪問檢查。
常用方法
public void setAccessible(boolean flag) throws SecurityException;將此對象的 accessible 標志設置為指示的布爾值。
- 參數為true,反射的對象在使用時應取消Java語言的訪問檢查
- 參數為false,應實施檢查
步驟:
3.5 由反射獲取成員變量并使用
反射機制中,類中的成員變量用Field類表示
Field提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)字段或實例字段。?
?
public Field getField(String name):?返回一個 Field對象,它反映此Class對象所表示的類或接口的指定公共成員字段。
public Field getDeclaredField(String name):返回一個Field對象,該對象反映此Class對象所表示的類或接口的指定已聲明字段。
public Field[ ] getFields():返回一個包含某些 Field對象的數組,這些對象反映此Class對象所表示的類或接口的所有可訪問公共字段。
public Field[ ] getDeclaredFields():返回Field對象的一個數組,這些對象反映此Class對象所表示的類或接口所聲明的所有字段。
Field ageField=c.getField("age");3.5 由反射創建對象獲取指定的成員變量,進行賦值與取值操作
步驟:
public void set(Object obj,Object value):?將指定對象變量上此Field對象表示的字段設置為指定的新值。
public Object get(Object obj):返回指定對象上此Field表示的字段的值。
Class c=Class.forName("Person");Constructor cons=c.getConstructor(String.class);Object obj=cons.newInstance("小明");Field nameF=c.getField("name");//用于后面獲得用此Field對象表示的成員變量的值 Field addressF=c.getField("address");addressF.setAccessible(true);addressF.set(obj,China);System.out.println("name"+=nameF.get(obj));3.6 由反射獲取成員方法并使用
反射機制中,類中的成員方法使用類Method表示
它提供關于類或接口上單獨某個方法(以及如何訪問該方法)的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)。?
public Object invoke(Object obj,Object...args):對帶有指定參數(args)的指定對象(obj)調用由此Method對象表示的底層方法。
返回方法的方法:
public Method getMethod(String name,Class<?> ...parameterTypes):?返回一個Method對象,它反映此Class對象所表示的類或接口的指定公共成員方法。
public Method getDeclaredMethod(Stirng name,Class<?>...parameterTypes):?返回一個Method對象,該對象反映此Class對象所表示的類或接口的指定已聲明方法。
public Method[ ] getMethods():返回一個包含某些Method對象的數組,這些對象反映此Class對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共成員方法。
public Method[ ] getDeclaredMethods():?返回Method對象的一個數組,這些對象反映此Class對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。
3.7 通過反射創建對象,調用指定方法
步驟:
3.8 泛型的擦除
程序編譯后產生的.class文件,是沒有泛型約束的
可通過反射,向有泛型約束的集合中,添加任意類型的元素。
ArrayList<Integer> list=new ArrayList<Integer>();list.add(new Integer(30));Class c=Class.forName("java.util.ArrayList");Method addM=c.getMethod("add",Object.class);addM.invoke(list,"haha");System.out.println(list);3.9 反射配置文件
通過反射配置文件,運行配置文件中指定的類的對應方法
讀取Properties.txt文件中的數據,通過反射技術,完成Person對象的創建
Properties.txt文件內容:
className=packageName.Person
methodName=method5
步驟:
?
總結
以上是生活随笔為你收集整理的类加载、类加载器、反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DBUtils、连接池
- 下一篇: 集合-1(Collection、迭代器、