反射 Reflect+JVM類加載

反射 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命令來運行某個主類真正在使用這個類型的時候

未完待續~~~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章