類加載器
程序使用某個類時角钩,該類還未被加載到內(nèi)存
系統(tǒng)通過類加載冈敛、類連接贴唇、類初始化三步驟對類進(jìn)行初始化
類加載
- 就是指將class文件讀入內(nèi)存丽柿,并為之創(chuàng)建一個
java.lang.Class
對象 - 任何類被使用時,系統(tǒng)都會為之建立一個
java.lang.Class
對象
類的連接
- 驗(yàn)證階段:用于檢驗(yàn)被加載的類是否有正確的內(nèi)部結(jié)構(gòu)蔗包,并和其他類協(xié)調(diào)一致
- 準(zhǔn)備階段:負(fù)責(zé)為類的類變量分配內(nèi)存秉扑,并設(shè)置默認(rèn)初始化值
- 解析階段:將類的二進(jìn)制數(shù)據(jù)中的符號引用替換為直接引用
類的初始化
- 在該階段,主要就是對類變量進(jìn)行初始化
類的初始化步驟
- 假如類還未被加載和連接,則程序先加載并連接該類
- 假如該類的直接父類還未被初始化舟陆,則先初始化其直接父類
- 假如類中有初始化語句误澳,則系統(tǒng)依次執(zhí)行這些初始化語句
- ps:執(zhí)行第2個步驟,系統(tǒng)對直接父類初始化步驟也遵循初始化步驟1-3
類的初始化時機(jī)
- 創(chuàng)建類的實(shí)例
- 調(diào)用類的類方法
- 訪問類或者接口的類變量秦躯,或者為該類變量賦值
- 使用反射方式來強(qiáng)制創(chuàng)建某個類或接口對應(yīng)的
java.lang.class
- 初始化某個類的子類
- 直接使用
java.exe
命令來運(yùn)行某個主類
類加載器
ClassLoader
:是負(fù)責(zé)加載類的對象
Java運(yùn)行時具有以下內(nèi)置類加載器
-
Bootstrap class loader
它是虛擬機(jī)的內(nèi)置類加載器忆谓,通常表示為null,并且無父null -
Platform class loader
平臺類加載器可以看到所有平臺類踱承,平臺類包括由平臺類加載器或其祖先定義的JavaSE平臺API倡缠,其實(shí)現(xiàn)類和JDK特定的運(yùn)行時類 -
System class loader
它也被稱為應(yīng)用程序類加載器,與平臺類加載器不同茎活。系統(tǒng)類加載器通常用于定義應(yīng)用程序類路徑昙沦,模塊路徑的JDK特定工具上的類 - 類加載器繼承關(guān)系
System的父類加載器為Platform
Platform的父類加載器為BootStrap
ClassLoader中的兩個方法
-
static ClassLoader getSystemClassLoader()
返回用于委派的系統(tǒng)類加載器 -
ClassLoader getParent()
返回父類加載器進(jìn)行委派
ClassLoader c=ClassLoader.getSystemClassLoader();
System.out.println(c);
ClassLoader c2=c.getParent();
System.out.println(c2);
ClassLoader c3=c2.getParent();
System.out.println(c3);
反射
反射概述
Java反射機(jī)制:指在運(yùn)行時去獲取一個類的變量和方法信息。然后通過獲取到的信息來創(chuàng)建對象妙色,調(diào)用方法的一種機(jī)制桅滋。這種動態(tài)性可以極大增強(qiáng)程序的靈活性,程序不用在編譯期就完成確定身辨,在運(yùn)行期仍可以擴(kuò)展
獲取Class類的對象
通過反射去使用一個類丐谋,首先要獲取該類的字節(jié)碼文件對象(類型為Class類型對象)
三種方式
- 使用類的class屬性來獲取該類對應(yīng)的Class對象
eg:Student.class將會返回Student類對應(yīng)的Class對象
- 調(diào)用對象的
getClass()
方法,返回該對所屬類對應(yīng)的Class對象(所有Java對象都可) - 使用Class類中的靜態(tài)方法
forName(String className)
煌珊,要傳入字符串參數(shù)号俐,值是某個類的全路徑,也就是完整包名的路徑
//使用類的class屬性來獲取該類對應(yīng)的Class對象
Class<Student> c1=Student.class;
System.out.println(c1);
//調(diào)用對象的`getClass()`方法定庵,返回該對所屬類對應(yīng)的Class對象
Student s=new Student();
Class<? extends Student> c2=s.getClass();
System.out.println(c2);
//使用Class類中的靜態(tài)方法forName(String className)
Class<?> c3=Class.forName("com.itheima01.Student");
System.out.println(c3);
反射獲取構(gòu)造方法并使用
-
Constructor<?>[] getConstructors()
:返回所有公共構(gòu)造方法對象的數(shù)組 -
Constructor<?>[] getDeclaredConstructors()
:返回所有構(gòu)造方法對象的數(shù)組 -
Constructor<T> getConstructor(Class<?>...parameterTypes)
:返回單個公共構(gòu)造方法對象 -
Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes)
:返回單個構(gòu)造方法對象 -
T newInstance(Object...initargs)
:根據(jù)指定的構(gòu)造方法創(chuàng)建對象
public class ReflectDemo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException
, IllegalAccessException, InvocationTargetException, InstantiationException {
//獲取Class對象
Class<?> c=Class.forName("com.itheima01.Student");
//Constructor<?>[] getConstructors():返回所有公共構(gòu)造方法對象的數(shù)組
Constructor<?>[] cons=c.getConstructors();
for(Constructor con:cons){
System.out.println(con);
}
//Constructor<?>[] getDeclaredConstructors():返回所有構(gòu)造方法對象的數(shù)組
Constructor<?>[] cons1=c.getDeclaredConstructors();
for(Constructor con:cons1){
System.out.println(con);
}
//Constructor<T> getConstructor(Class<?>...parameterTypes):返回單個公共構(gòu)造方法對象
//Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):返回單個構(gòu)造方法對象
//參數(shù):你要獲取的構(gòu)造方法的參數(shù)個數(shù)和數(shù)據(jù)類型對應(yīng)的字節(jié)碼文件對象
Constructor<?> con=c.getConstructor();
//Constructor提供了一個類的單個構(gòu)造函數(shù)的信息和訪問權(quán)限
/*T newInstance(Object...initargs)使用由此Constructor對象表示的構(gòu)造函數(shù)
使用指的的初始化參數(shù)來創(chuàng)建和初始化構(gòu)造函數(shù)的聲明類的新實(shí)例*/
Object obj=con.newInstance();
System.out.println(obj);
}
}
練習(xí)1
Class<?> c=Class.forName("com.itheima01.Student");
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
//基本數(shù)據(jù)類型也可以通過.class得到對應(yīng)的Class類型
Object obj=con.newInstance("林青霞",30,"西安");
System.out.println(obj);
練習(xí)2
Class<?> c=Class.forName("com.itheima01.Student");
Constructor<?> con = c.getDeclaredConstructor(String.class);
//暴力反射
//public void setAccessible(boolean flag):值為true,取消訪問檢查
con.setAccessible(true);
Object obj=con.newInstance("林青霞");
System.out.println(obj);
反射獲取成員變量并使用
-
Field[] getFields
:返回所有公共成員變量對象的數(shù)組 -
Field[] getDeclaredFields
:返回所有成員變量對象的數(shù)組 -
Field getField(String name)
:返回單個公共成員變量對象 -
Field getDeclaredField(String name)
:返回單個成員變量對象 -
void set(Object obj,Object value)
將指定的對象參數(shù)中,由此Field對象表示的字段吏饿,設(shè)置為指定的新值
public class ReflectDemo04 {
public static void main(String[] args) throws ....... {
Class<?> c=Class.forName("com.itheima01.Student");
//Field[] getFields:返回所有公共成員變量對象的數(shù)組
//Field[] getDeclaredFields:返回所有成員變量對象的數(shù)組
Field[] fields=c.getFields();
Field[] fields1=c.getDeclaredFields();
for(Field field:fields){
System.out.println(field);
}
//Field getField(String name):返回單個公共成員變量對象
//Field getDeclaredField(String name):返回單個成員變量對象
Field addressField=c.getField("address");
//獲取無參構(gòu)造方法創(chuàng)建對象
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
//Field提供有關(guān)類或接口的單個字段的信息的動態(tài)訪問
addressField.set(obj,"西安");
System.out.println(obj);
}
}
練習(xí)
Class<?> c=Class.forName("com.itheima01.Student");
Constructor<?> con = c.getConstructor();
Object obj=con.newInstance();
System.out.println(obj);
//s.name="林青霞"
Field nameField=c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"林青霞");
//s.age=20
Field ageField=c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj,30);
//s.address="西安"
Field addressField=c.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"西安");
System.out.println(obj);
反射獲取成員方法并使用
-
Method[] getMethods()
:返回所有公共成員方法對象的數(shù)組,包括繼承的 -
Method[] getDeclaredMethods()
:返回所有成員方法對象的數(shù)組蔬浙,不包括繼承的 -
Method getMethod(String name,Class<?>...patameterTypes)
:返回單個公共成員方法對象 -
Method getDeclaredMethod(String name,Class<?>...parameterTypes)
:返回單個成員方法對象 -
Object invoke(Object obj,Object...args)
:在具有指定參數(shù)的指定對象上調(diào)用此方法對象表示的基礎(chǔ)方法
public class ReflectDemo06 {
public static void main(String[] args) throws ......{
Class<?> c=Class.forName("com.itheima01.Student");
//Method[] getMethods():返回所有公共成員方法對象的數(shù)組猪落,包括繼承的
//Method[] getDeclaredMethods():返回所有成員方法對象的數(shù)組,不包括繼承的
Method[] methods=c.getMethods();
for(Method method:methods){
System.out.println(method);
}
//Method getMethod(String name,Class<?>...patameterTypes):返回單個公共成員方法對象
//Method getDeclaredMethod(String name,Class<?>...parameterTypes):返回單個成員方法對象
Method m = c.getMethod("method1");
//獲取無參構(gòu)造方法創(chuàng)造對象
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
//Object invoke(Object obj,Object...args):在具有指定參數(shù)的指定對象上調(diào)用此方法對象表示的基礎(chǔ)方法
//Object:返回值類型畴博;obj:調(diào)用方法的對象笨忌;args:方法需要的參數(shù);
m.invoke(obj);
}
}
練習(xí)
Class<?> c=Class.forName("com.itheima01.Student");
//Student s=new Student();
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
//s.method1();
Method m1 = c.getMethod("method1");
m1.invoke(obj);
//s.method2("林青霞")
Method m2 = c.getMethod("Method2", String.class);
m2.invoke(obj,"林青霞");
//String ss=s.method3("林青霞",30);System.out.println(ss)
Method m3 = c.getMethod("method3", String.class, int.class);
Object o = m3.invoke("林青霞", 30);
System.out.println(o);
//s.function();
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
反射練習(xí)
越過泛型檢查
有一個ArrayList<Integer>集合俱病,在這個集合中添加一個字符串?dāng)?shù)據(jù)官疲,實(shí)現(xiàn)如下
(正常情況字符串無法添加到Integer類型集合中)
public class ReflectTest01 {
public static void main(String[] args) throws ...... {
//創(chuàng)建集合
ArrayList<Integer> array=new ArrayList<>();
Class<? extends ArrayList> c=array.getClass();
//反射可以越過泛型檢查,獲取原始方法所需要參數(shù)類型
Method m = c.getMethod("add", Object.class);
m.invoke(array,"hello");
m.invoke(array,"world");
m.invoke(array,"java");
System.out.println(array);
}
}
運(yùn)行配置文件指定內(nèi)容
//class.txt文件
className=com.itheima03.Student
methodName=study
//Student類
public class Student {
public void study(){
System.out.println("好好學(xué)習(xí)亮隙,天天向上");
}
}
//反射測試
public class ReflectTest02 {
public static void main(String[] args) throws ...... {
/*class.txt
className=xxx
methodName=xxx */
//加載數(shù)據(jù)
Properties prop=new Properties();
FileReader fr=new FileReader("myReflect\\class.txt");
prop.load(fr);
fr.close();
/* 已獲得數(shù)據(jù)
className=com.itheima03.Student
methodName=study
*/
String className=prop.getProperty("className");
String methodName=prop.getProperty("methodName");
//通過反射來使用
Class<?> c=Class.forName(className);
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
Method m = c.getMethod(methodName);
m.invoke(obj);
}
}