反射 Reflect
概念:在程序運行的時候 動態的加載類和類的信息。
三種方式獲取類類型:Class
- 類名.class;
- 對象.getClass();
- Class.forName(“全類名”);
創建對象(已Person爲例)
- Person
package com.qianfeng.reflects;
public class Person {
private String name;
private Integer age;
private String add;
public String gender;
public Person() {
super();
System.out.println("Empty-construct");
}
public Person(String name, Integer age, String add) {
super();
this.name = name;
this.age = age;
this.add = add;
System.out.println("full-construct");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAdd() {
return add;
}
public void setAdd(String add) {
this.add = add;
}
private void hello() {
System.out.println("hi.......");
}
public void hi() {
System.out.println("hello...");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", add=" + add + "]";
}
}
- 空參構造
Class cls=p.getClass();
Person p=(Person)cls.newInstance();
- 有參構造
Class cls=Person.class;
Constructor<Person> constructor = c2.getConstructor(Integer.class,String.class,Integer.class);//設置參數類類型
Person newInstance = constructor.newInstance(1,"zs",18);//設置具體參數
通過反射《操作》成員屬性
-
可見的屬性
Class cls=Person.class; Field f=cls.getField("屬性名"); //獲得這個屬性的值 Object obj=f.get(person的對象);//記得根據自己本身屬性的類型去轉型 ------------------------------ f.set(person的對象,具體的值);
-
不可見的屬性
Field f = c3.getDeclaredField("name");//獲得一個私有的屬性 f.setAccessible(true);//設置屬性的可見性 String name=(String)f.get(newInstance);//獲得私有屬性值 System.out.println(name); ----------------------------- f.set(person的對象,具體的值);
反射獲取構造函數
- 定義
- Class類的new Instance()方法是使用該類無參的構造函數創建對象
- 如果一個類沒有無參的構造函數, 就不能這樣創建了,可以調用Class類的getConstructor(String.class,int.class)方法獲取一個指定的構造函數然後再調用Constructor類的newInstance(“張三”,20)方法創建對象
- 參構造方法(以person爲例,有兩個構造方法,一個帶參,一個不帶參)
@org.junit.jupiter.api.Test
void test() throws Exception {
Class c=Person.class;
Person po=(Person)c.newInstance();//獲取有參構造方法
Constructor[] constructors = c.getConstructors();//獲取所有構造方法
for(Constructor c1:constructors) {
Parameter[] p = c1.getParameters();//獲取某個構造方法的參數
for(Parameter p1:p) {
//p1.getName(); 參數名--價值不大,arg0;
//p1.getType() 參數類型
System.out.println("其中的一個構造方法中的參數類型"+":"+p1.getType());
}
}
}
反射獲取成員變量
- 方法–c.getDeclaredFields();
@org.junit.jupiter.api.Test
void test2() throws Exception{
Class c=Person.class;
Field[] dFs = c.getDeclaredFields();//全部成員屬性類型信息--任意權限
Field[] fields = c.getFields();//只有public權限的屬性可以獲得
System.out.println(Arrays.toString(dFs));
/*
[
private java.lang.String com.qianfeng.reflects.Person.name,
private java.lang.Integer com.qianfeng.reflects.Person.age,
private java.lang.String com.qianfeng.reflects.Person.add,
]
遍歷dFs中內容--對象.getName()--成員遍歷名
Class<?> type=對象.getType()--成員類型
*/
}
反射獲取成員方法
- Class.getMethod(String, Class…) —獲取成員方法–//本類中的方法
- Class.getDeclaredMethod(String, Class…)–獲取成員方法–//全部方法=自己的方法+繼承的父類方法
- invoke(Object, Object…)–調用成員方法
@org.junit.jupiter.api.Test
void test3() throws Exception{
Class<?> c=Person.class;
Method[] dMs = c.getDeclaredMethods();//本類中的方法
//System.out.println(Arrays.toString(dMs));
Method[] methods = c.getMethods();//全部方法=自己的方法+繼承的父類方法
System.out.println(Arrays.toString(methods));//全部方法
//=========================
//想調用對象,先實例化對象--反射的方式,然後調用invoke()函數
Person p=(Person)c.newInstance();
Method method = c.getMethod("hi");
method.invoke(p);
//想調用私有化函數需加這句 method.setAccessible(true);
//Method 對象 m.invoke(實例化對象,傳入的參數(可不填))
//如果返回值 ,設置如: int n=m.invoke(p)
/*
dMs [
public java.lang.String com.qianfeng.reflects.Person.toString(),
public java.lang.String com.qianfeng.reflects.Person.getName(),
public void com.qianfeng.reflects.Person.setName(java.lang.String),
public java.lang.Integer com.qianfeng.reflects.Person.getAge(),
public void com.qianfeng.reflects.Person.setAge(java.lang.Integer),
public java.lang.String com.qianfeng.reflects.Person.getAdd(),
public void com.qianfeng.reflects.Person.setAdd(java.lang.String),
private void com.qianfeng.reflects.Person.hello()
]
遍歷dFs中內容--對象.getName()--成員遍歷名
Class<?> type=對象.getType()--成員類型
*/
}
JVM類加載
- 定義
- 當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現對這個類進行初始化
- 加載
- 就是指將.class文件讀入內存,併爲之創建一個Class對象。任何類被使用時系統都會建立一個Class對象。
- 連接
- 驗證 是否有正確的內部結構,並和其他類協調一致
- 準備 負責爲類的靜態成員分配內存,並設置默認初始化值
- 解析 將類的二進制數據中的符號引用替換爲直接引用
- 初始化
- 就是我們以前講過的初始化步驟
- 加載的時機
- 創建類的實例
- 訪問類的靜態變量,或者爲靜態變量賦值
- 調用類的靜態方法
- 使用反射方式來強制創建某個類或接口對應的java.lang.Class對象
- 加載某個類的子類
- 直接使用java.exe命令來運行某個主類真正在使用這個類型的時候