類加載器
(1)類的加載
當我們的程序在運行后,第一次使用某個類的時候,會將此類的class文件讀取到內存,并將此類
的所有信息存儲到一個Class對象中。
說明:
a.圖中的Class對象是指:JAVA.lang.Class類的對象,此類由Java類庫提供,專門用于存儲類的信息。
b.我們程序中可以通過:"類名.class",或者"對象.getClass()"方法獲取這個Class對象
(2)類的加載時機
a.創建類的實例。
b.調用類的靜態變量,或者為靜態變量賦值。
c.調用類的靜態方法。
d.使用反射方式來強制創建某個類或接口對應的java.lang.Class對象。
e.初始化某個類的子類。
f.直接使用java.exe命令來運行某個主類。
以上六種情況的任何一種,都可以導致JVM將一個類加載到方法區。
(3)類加載器
類加載器:是負責將磁盤上的某個class文件讀取到內存并生成Class的對象。
Java中有三種類加載器,它們分別用于加載不同種類的class:
a.啟動類加載器(Bootstrap ClassLoader):用于加載系統類庫<JAVA_HOME>bin目錄下的class,例如:rt.jar。
b.擴展類加載器(Extension ClassLoader):用于加載擴展類庫<JAVA_HOME>libext目錄下的class。
c.應用程序類加載器(Application ClassLoader):用于加載我們自定義類的加載器。
public class Test{ public static void main(String[] args) {
System.out.println(Test.class.getClassLoader());//sun.misc.Launcher$AppClassLoader
System.out.println(String.class.getClassLoader());//null(API中說明:一些實現 可能使用null來表示引導類加載器。 如果此類由引導類加載器加載,則此方法將在此類實現中返回null。 )
}
}
(4)雙親委派機制
上圖展示了"類加載器"的層次關系,這種關系稱為類加載器的"雙親委派模型":
a."雙親委派模型"中,除了頂層的啟動類加載器外,其余的類加載器都應當有自己的"父級類加載器"。
b.這種關系不是通過"繼承"實現的,通常是通過"組合"實現的。通過"組合"來表示父級類加載器。
c."雙親委派模型"的工作過程:
i. 某個"類加載器"收到類加載的請求,它首先不會嘗試自己去加載這個類,而是把請求交給父
級類加載器。
ii.因此,所有的類加載的請求最終都會傳送到頂層的"啟動類加載器"中。
iii.如果"父級類加載器"無法加載這個類,然后子級類加載器再去加載。
(5)雙親委派機制的好處
雙親委派機制的一個顯而易見的好處是:Java的類隨著它的類加載器一起具備了一種帶有優先級的層次
關系。例如:java.lang.Object。它存放在rt.jar中。無論哪一個類加載器要加載這個類,最終都是委派
給處于頂端的"啟動類加載器"進行加載,因此java.lang.Object類在程序的各種類加載器環境中都是同一
個類。
相反,如果沒有"雙親委派機制",如果用戶自己編寫了一個java.lang.Object,那么當我們編寫其它類
時,這種隱式的繼承使用的將會是用戶自己編寫的java.lang.Object類,那將變得一片混亂。
反射的概述
(1)反射的引入
問題:IDEA中的對象是怎么知道類有哪些屬性,哪些方法的呢?
答:通過反射技術對象類進行了解剖得到了類的所有成員。
(2)反射的概念
反射是一種機制,利用該機制可以在程序運行過程中對類進行解剖并操作類中的所有成員(成員變量,成員方 法,構造方法)。
(3)使用反射操作類成員的前提
要獲得該類字節碼文件對象,就是Class對象。
(4)反射在實際開發中的應用
a.開發IDEA(集成開發環境),比如IDEA,Eclipse
b.各種框架的設計和學習 比如Spring,Mybaits....
Class對象的獲取方式
(1)三種獲取方式
方式1: 通過類名.class獲得
方式2:通過對象名.getClass()方法獲得
方式3:通過Class類的靜態方法獲得: static Class forName("類全名")
每一個類的Class對象都只有一個。
示例代碼:
package com.test.code.reflex;
public class Student {
}
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
// 獲得Student類對應的Class對象
Class<Student> c1 = Student.class;
// 創建學生對象
Student stu = new Student();
Class<? extends Student> c2 = stu.getClass();
System.out.println(c1 == c2);
// 通過Class類的靜態方法獲得: static Class forName("類全名")
Class<?> c3 = Class.forName("com.test.code.reflex.Student");
System.out.println(c1 == c3);
System.out.println(c2 == c3);
}
}
Demo01運行結果:
(2)Class類常用方法
String getSimpleName(); 獲得類名字符串:類名
String getName(); 獲得類全名:包名+類名
T newInstance() ; 創建Class對象關聯類的對象
示例代碼:
public class Demo02 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
// 獲得Class對象
Class<Student> c = Student.class;
// 獲得類名字符串:類名
System.out.println(c.getSimpleName());
// 獲得類全名:包名 + 類名
System.out.println(c.getName());
// 創建對象
Student stu = (Student)c.newInstance();
System.out.println(stu);
}
}
Demo02運行結果:
4.反射之操作構造方法
(1)Constructor類概述
反射之操作構造方法的目的:獲得Constructor對象來創建類的對象。
Constructor類概述:類中的每一個構造方法都是一個Constructor類的對象
(2)Class類中與Constructor相關的方法
1. Constructor getConstructor(Class... parameterTypes)
* 根據參數類型獲得對應的Constructor對象。
* 只能獲得public修飾的構造方法
2. Constructor getDeclaredConstructor(Class... parameterTypes)
* 根據參數類型獲得對應的Constructor對象
* 可以是public、protected、(默認)、private修飾符的構造方法。
3. Constructor[] getConstructors()
* 獲得類中的所有構造方法對象,只能獲得public的
4. Constructor[] getDeclaredConstructors()
* 獲得類中的所有構造方法對象
* 可以是public、protected、(默認)、private修飾符的構造方法。
(3)Constructor對象常用方法
1. T newInstance(Object... initargs)"—— 根據指定的參數創建對象
2. void setAccessible(true) 設置"暴力反射"——是否取消權限檢查,true取消權限檢查,false表示不取消
示例代碼:
public class Student {
private String name;
private String sex;
private int age;
//公有構造方法
public Student(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
//私有構造方法
private Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
}
public class Demo03 {
/**
* Constructor[] getConstructors()
* 獲得類中的所有構造方法對象,只能獲得public的
* Constructor[] getDeclaredConstructors()
* 獲得類中的所有構造方法,包括private修飾的
*/
@Test
public void test03(){
// 獲得Class對象
Class<Student> c = Student.class;
// 獲得類中的所有構造方法對象,只能是public修飾的
Constructor<?>[] cons_one = c.getConstructors();
for (Constructor<?> con : cons_one) {
System.out.println(con);
}
System.out.println("--------------------------------");
// 獲取類中所有的構造方法,包括public、protected、(默認)、private的
Constructor<?>[] cons_two = c.getDeclaredConstructors();
for (Constructor<?> con : cons_two) {
System.out.println(con);
}
}
/**
* Constructor getDeclaredConstructor(Class... parameterTypes)
* 根據參數類型獲得對應的Constructor對象
*/
@Test
public void test02() throws Exception {
// 獲得Class對象
Class<Student> c = Student.class;
// 獲得兩個參數構造方法對象
Constructor<Student> con = c.getDeclaredConstructor(String.class, String.class);
// 取消權限檢查(暴力反射)
con.setAccessible(true);
// 根據構造方法創建對象
Student stu = con.newInstance("liuyifei", "女");
System.out.println(stu);
}
/**
* Constructor getConstructor(Class... parameterTypes)
* 根據參數類型獲得對應的Constructor對象
*/
@Test
public void test01() throws Exception {
// 獲得Class對象
Class<Student> c = Student.class;
// 獲得無參數構造方法對象 注意:記得在Student類中加無參構造方法,不然會報錯
Constructor<Student> con = c.getConstructor();
// 根據構造方法創建對象
Student student = con.newInstance();
System.out.println(student);
// 獲得有參數的構造方法對象
Constructor<Student> con2 = c.getConstructor(String.class, String.class, int.class);
// 創建對象
Student stu2 = con2.newInstance("jack", "男", 18);
System.out.println(stu2);
}
}
5.反射之操作成員方法
(1)Method類概述
反射之操作成員方法的目的:操作Method對象來調用成員方法
Method類概述:每一個成員方法都是一個Method類的對象。
(2)Class類中與Method相關的方法
* Method getMethod(String name,Class...args);
根據方法名和參數類型獲得對應的構造方法對象,只能獲得public的
* Method getDeclaredMethod(String name,Class...args);
根據方法名和參數類型獲得對應的構造方法對象,包括public、protected、(默認)、private的
* Method[] getMethods();
獲得類中的所有成員方法對象,返回數組,只能獲得public修飾的且包含父類的
* Method[] getDeclaredMethods();
獲得類中的所有成員方法對象,返回數組,只獲得本類的,包括public、protected、(默認)、 private的
(3)Method對象常用方法
* Object invoke(Object obj, Object... args)
調用指定對象obj的該方法
args:調用方法時傳遞的參數
* void setAccessible(true)
設置"暴力訪問"——是否取消權限檢查,true取消權限檢查,false表示不取消
示例代碼:
public class Demo04 {
/**
* Method[] getMethods();
* 獲得類中的所有成員方法對象,返回數組,只能獲得public修飾的且包含父類的
* Method[] getDeclaredMethods();
* 獲得類中的所有成員方法對象,返回數組,只獲得本類的,包含private修飾的
*/
@Test
public void test03() {
// 獲得Class對象
Class<Student> c = Student.class;
// 獲得類中的所有成員方法對象,返回數據,只能獲得public修飾的且包含父類的
// Method[] methods = c.getMethods();
// 獲得類中的所有成員方法對象,返回數組,只獲得本類的,包含private修飾的
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
/**
* Method getDeclaredMethod(String name,Class...args);
* 根據方法名和參數類型獲得對應的構造方法對象,
*/
@Test
public void test02() throws Exception {
// 獲得Class對象
Class<Student> c = Student.class;
// 根據Class對象創建學生對象
Student stu = c.newInstance();
// 獲得sleep方法對應的Method對象
Method m = c.getDeclaredMethod("sleep");
// 暴力反射
m.setAccessible(true);
// 通過m對象執行sleep方法
m.invoke(stu);
}
/**
* Method getMethod(String name,Class...args);
* 根據方法名和參數類型獲得對應的構造方法對象,
*/
@Test
public void test01() throws Exception {
// 獲得Class對象
Class<Student> c = Student.class;
// 根據Class對象創建學生對象
Student stu = c.newInstance();
// // 獲得study方法對應的Method對象
// Method m = c.getMethod("study");
// // 通過m對象執行study方法
// m.invoke(stu);
// 獲得study方法對應的Method對象
Method m2 = c.getMethod("study", int.class);
// 通過m2對象執行study方法
m2.invoke(stu, 8);
}
}
6.反射之操作成員變量
(1)Field類概述
反射之操作成員變量的目的 :通過Field對象給對應的成員變量賦值和取值
Field類概述: 每一個成員變量都是一個Field類的對象。
(2)Class類中與Field相關的方法
Field getField(String name);
根據成員變量名獲得對應Field對象,只能獲得public修飾
Field getDeclaredField(String name);
根據成員變量名獲得對應Field對象,包括public、protected、(默認)、private的
Field[] getFields();
獲得所有的成員變量對應的Field對象,只能獲得public的
Field[] getDeclaredFields();
獲得所有的成員變量對應的Field對象,包括public、protected、(默認)、private的
(3)Field對象常用方法
void set(Object obj, Object value)
void setInt(Object obj, int i)
void setLong(Object obj, long l)
void setBoolean(Object obj, boolean z)
void setDouble(Object obj, double d)
Object get(Object obj)
int getInt(Object obj)
long getLong(Object obj)
boolean getBoolean(Object ob)
double getDouble(Object obj)
void setAccessible(true); // 暴力反射,設置為可以直接訪問私有類型的屬性。
Class getType(); // 獲取屬性的類型,返回Class對象。
setXxx方法都是給對象obj的屬性設置使用,針對不同的類型選取不同的方法。
getXxx方法是獲取對象obj對應的屬性值的,針對不同的類型選取不同的方法。
示例代碼:
public class Student {
public String name;
private String gender;
public String toString() {
return "Student [name = " + name + " , gender = " + gender + "]";
}
}
public class Demo05 {
/**
* Field[] getFields();
* 獲得所有的成員變量對應的Field對象,只能獲得public的
* Field[] getDeclaredFields();
* 獲得所有的成員變量對應的Field對象,包含private的
*/
@Test
public void test02(){
// 獲得Class對象
Class<Student> c = Student.class;
// 獲得所有的成員變量對應的Field對象
// Field[] fields = c.getFields();
// 獲得所有的成員變量對應的Field對象,包括private
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
/**
* Field getField(String name);
* 根據成員變量名獲得對應Field對象,只能獲得public修飾
* Field getDeclaredField(String name);
* 根據成員變量名獲得對應Field對象,包含private修飾的
*/
@Test
public void test01() throws Exception {
// 獲得Class對象
Class<Student> c = Student.class;
// 創建對象
Student stu = c.newInstance();
// 獲得成員變量name對應的Field對象
Field f = c.getField("name");
// 給成員變量name賦值
// 給指定對象stu的name屬性賦值為jack
f.set(stu,"jack");
// 獲得指定對象stu成員變量name的值
System.out.println(f.get(stu)); // jack
// 獲得成員變量的名字
System.out.println(f.getName()); //name
// 給成員變量gender賦值
// 獲得成員變量gender對應的Field對象
Field f1 = c.getDeclaredField("gender");
// 暴力反射
f1.setAccessible(true);
// 給指定對象stu的gender屬性賦值為男
f1.set(stu,"男");
System.out.println(stu);
}
}
wx搜索“自律的西瓜L”