淺談java中的反射

秋水長天發表於2019-11-11

1.反射

程式執行時,允許程式結構或者變數的型別,這種語言成為動態語言,如Python,Puby是動態語言,顯然java不是動態語言,但是java有一個非常突出的動態相關機制:Reflection--反射.

反射定義:java反射機制是在執行狀態中,對於任意一個類,都能知道這個類的所有屬性和方法,對於任意一個物件,都能夠呼叫它的任意一個方法和屬性,這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制

一般情況下,我們在使用一個類時,是先獲得一個類,然後例項化這個類,但是通過反射我們可以通過一個物件獲取到類中的資訊.

java的反射機制可以實現的功能:

1.在執行時判斷任意一個物件所屬的類;

2.在執行時構造任意一個類的物件;

3.在執行時判斷任意一個類所具備的成員變數和方法;

4.在執行時呼叫任意一個物件的方法

5.生成動態代理

2.獲取Class

使用反射機制最先應該獲取Class物件.Class物件就是反射的源頭.java中的反射機制.

當一個類被載入後.java虛擬機器就會自動產生一個Class物件,一個類只會生成一個Class物件.在Class物件中存在著這個類中的所有內容,比如成員屬性,成員方法,構造方法

1.獲取Class物件的方法


1.物件.getClass()

2.類名.class

3.Class.forname("包名+類名")

例子1:

        public class Demo1 {
        	public static void main(String[] args) throws ClassNotFoundException {
        		// 1.類名.class
        		Class<String> cls1 = String.class;
        		System.out.println(cls1);
        		// 2.物件.getClass()
        		Class<? extends String> cls2 = "哈哈".getClass();
        		System.out.println(cls2);
        		// 3.Class.forName("包名+類名")
        		Class<?> cls3 = Class.forName("java.lang.Object");
        		System.out.println(cls3);
        		// 根據包裝型別.TYPE屬性獲取對應基本資料型別的Class物件
        		Class<Integer> cls7 = Integer.TYPE;
        		System.out.println(cls7);
        		Class cls5 = int.class;
        		System.out.println(cls5);
        	}
        }
複製程式碼

三種使用方式主要使用第三種,第一種我們已經有了物件,所以用反射的意義不大.第二種需要導包,不導包編譯就不通過,依賴性太強.所以我們主要使用第三種,我們可以直接傳入字串也可以把字串寫在配置檔案中.

3.通過反射獲取構造方法

我們先定義一個Person類:

 public class Person {
        	private String name;
        	private int age;
        	private String id;
        
        	public Person() {
        		System.out.println("我是空參構造");
        	}
        
        	private Person(String id) {
        		this.id = id;
        		System.out.println("我是私有單參構造");
        	}
        
        	public Person(String name, int age, String id) {
        		this.name = name;
        		this.age = age;
        		this.id = id;
        		System.out.println("我是公共三參構造");
        	}
        
        	public String getName() {
        		return name;
        	}
        
        	public void setName(String name) {
        		this.name = name;
        	}
        
        	public int getAge() {
        		return age;
        	}
        
        	public void setAge(int age) {
        		this.age = age;
        	}
        
        	public String getId() {
        		return id;
        	}
        
        	public void setId(String id) {
        		this.id = id;
        	}
        
        	@Override
        	public String toString() {
        		return "[name=" + name + ", age=" + age + ", id=" + id + "]";
        	}
        }
複製程式碼

1.獲取構造方法


通過反射可以獲取一個類的構造方法

例子2:

public class Simple {
    	public static void main(String[] args) throws NoSuchMethodException, SecurityException {
    		// 獲得Person類的Class物件
    		Class<Person> cla = Person.class;
    
    		// 獲得Person類中的構造方法,利用getConstructors()方法可以獲得此類公共構造方法的 Constructor 物件陣列
    		Constructor<Person>[] con = (Constructor<Person>[]) cla.getConstructors();
    		System.out.println(Arrays.toString(con));
    
    		// 利用getConstructor()方法可以獲得指定的公共構造方法,可根據傳入的引數返回相應的構造方法
    		Constructor<Person> con1 = cla.getConstructor(String.class, int.class, String.class);
    		System.out.println(con1);
    
    		// 利用getDeclaredConstructors()方法可以獲得此類所有已宣告的構造方法的 Constructor 物件的陣列
    		Constructor<Person>[] con2 = (Constructor<Person>[]) cla.getDeclaredConstructors();
    		System.out.println(Arrays.toString(con2));
    
    		// 利用getDeclaredConstructor()方法可以返回一個 Constructor 物件,該物件反映此 Class
    		// 物件所表示的類或介面的指定構造方法
    		Constructor<Person> con3 = cla.getDeclaredConstructor(String.class);
    		System.out.println(con3);
    	}
    }
複製程式碼

程式執行結果:

 [public com.shy.test.Person(java.lang.String,int,java.lang.String), public com.shy.test.Person()]
    public com.shy.test.Person(java.lang.String,int,java.lang.String)
    [public com.shy.test.Person(java.lang.String,int,java.lang.String), private com.shy.test.Person(java.lang.String), public com.shy.test.Person()]
    private com.shy.test.Person(java.lang.String)
複製程式碼

4.通過反射獲取成員變數使用

1.批量的

Field[] getFields():獲取所有的"公有欄位"
複製程式碼
Field[] getDeclaredFields():獲取所有欄位,包括:私有.受保護.預設.公有
複製程式碼

2.獲取單個的

public Field getField(String fieldName):獲取某個"公有的"欄位
複製程式碼
public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
複製程式碼

例子4:

import java.lang.reflect.Field;

        public class Simple {
        	public static void main(String[] args) throws Exception {
        		// 獲得Person類的Class物件
        		Class<Person> cla = Person.class;
        
        		//獲取欄位
        		System.out.println("---------------獲取所有的屬性(包括私有、受保護、預設的)-------------");
        		Field[]fields=cla.getDeclaredFields();
        		for(Field f:fields){
        			System.out.println(f);
        		}
        		System.out.println("-----------------獲得屬性並呼叫--------------------------");
        		//獲取屬性並呼叫
        		Field f=cla.getDeclaredField("name");
        		System.out.println(f);
        		//獲取一個物件
        		Person p=cla.getConstructor().newInstance();
        		//放開許可權
        		f.setAccessible(true);
        		/*		通過set(Object obj,Object value)方法設定屬性值
        		 * 		obj:要設定的欄位所在的物件
        		 * 		value:要為欄位設定的值
        		 */
        		f.set(p,"zhangsan");
        		System.out.println(p);
        	}
        }
複製程式碼

程式執行結果:

 ---------------獲取所有的屬性(包括私有、受保護、預設的)-------------
    private java.lang.String com.shy.test.Person.name
    private int com.shy.test.Person.age
    private java.lang.String com.shy.test.Person.id
    -----------------獲得屬性並呼叫--------------------------
    private java.lang.String com.shy.test.Person.name
    我是空參構造
    [name=zhangsan, age=0, id=null]
複製程式碼

相關文章