1. 程式人生 > >黑馬程式設計師-----java反射總結*

黑馬程式設計師-----java反射總結*

---------------------- ASP.Net+Android+IOS開發.Net培訓、期待與您交流! ----------------------

一、java的反射機制概述

反射和類的關係:在程式執行狀態中,對於任意一個類(指.class檔案),都能夠知道這個類所有的屬性和方法

反射和類物件的關係:反射對於某個類的物件,都能夠呼叫它的任意一個方法和屬性

概念:動態獲取類的資訊以及動態呼叫類物件的方法和屬性的功能稱為java語言的反射機制

好處:提高了程式的擴充套件性

該好處與多型的好處比較:通過反射可以省略new子類物件這個步驟,直接將類名以字串的形式傳遞到forName的引數列表中來建立此類例項

Java反射有什麼作用呢?

假如我們有兩個程式設計師,一個程式設計師在寫程式的時候,需要使用第二個程式設計師所寫的類,但第二個程式設計師並沒完成他所寫的類。那麼第一個程式設計師的程式碼能否通過編譯呢?這是不能通過編譯的。利用Java反射的機制,就可以讓第一個程式設計師在沒有得到第二個程式設計師所寫的類的時候,來完成自身程式碼的編譯。


二、Class類物件的獲取方法

1、java對位元組碼(.class)檔案進行了抽象,用class類來描述

2、Class物件的原始碼:public final class Class<T>{.......}

     final:表示該類不能夠被繼承

     Class類是一個泛型類,T表示Class類物件所屬哪個類

     Class類沒有構造方法,不能夠new物件,這種方式是絕對錯誤的:Class c = new Class();

3、獲取Class類物件的五種途徑

  • 非靜態方法getClass():物件名.getClass()

缺點:此種方式建立類物件還需要明確類並建立物件

  • 靜態屬性:class:屬性名.class(屬性可以是陣列、字串、基本資料型別、類等)
缺點:此種方式建立類物件也需要明確類,擴充套件性差
  • 靜態方法Class.forName():引數列表中傳入某類的全類名(例如java.lang.Integer)

優點:僅僅需要類名以字串的形式傳入即可獲得class類物件,這種方式最為常見,最為簡單

  • 非靜態方法getSuperclass:物件名.getSuperclass()
此種方式是返回該類Class物件的父類的Class物件
  • TYPE
包裝類的專屬建立Class物件方式

面試題:以上方法的作用是?

作用:返回某個類的位元組碼檔案物件,也就是Class物件

注意:

1、如果位元組碼檔案已被載入,那麼forName直接返回

2、如果位元組碼檔案還未載入,那麼JVM就指示類載入器去載入該檔案,並把載入完的位元組碼檔案放入緩衝區,再返回

3、Class物件的常用方法

八種基本資料型別對應八個Class例項物件

基本資料型別對應的Class例項物件不等於包裝類對應的Class例項物件

只要是資料型別,就有對應的例項物件

1、獲取空引數構造方法並建立物件實體

獲取空參構造方法:public T newInstance() throws InstantiationException,IllegalAccessException;

InstantiationException異常:如果該類中沒有空參構造 方法,則報該異常

IllegalAccessException異常:如果該類中預設空參構造方法的許可權修飾符是private而不是public,則報該異常

public static void getConstructor1(){  
    try{  
       Stringname ="cn.itcast.Person";  
       Class clazz =Class.forName(name); 
       //呼叫newInstance方法時,會自動呼叫Person類的空參構造方法建立Person物件 
       Objectob j = clazz.newInstance();  
    }catch(ClassNotFoundException cnfe){  
       sop(cnfe.toString());  
    }catch(InstantiationException ite){  
       sop(ite.toString());  
    }catch(IllegalAccessException iae){  
       sop(iae.toString());  
    }  
}  

2、獲取非空引數構造方法並建立愛你物件實體

獲取非空引數構造方法:getConstructor方法 public Constructor<T> getConstructor(Class<?> ...parameterTypes) throws NosuchMethodWxception,SecurityException

package cn.itcast.ly;

import java.lang.reflect.*;

public class Demo {
	public static void main(String[] args) throws Exception{
		//第一步:建立Class物件例項
		Class cla = Class.forName("cn.itcast.ly.Person");
		//第二步:建立一個數組
		Class[] clas = new Class[]{String.class,int.class};
		//第三步:獲取構造方法Class類實體
		Constructor con = cla.getConstructor(clas);
		//第四步:根據Constructor類的newInstance方法建立實體,
		//原始碼:public T newInstance(Object... initargs)
		Object[] objs = new Object[]{"Tom",20}; 
		Object obj = con.newInstance(objs);
		//第五步:列印
		System.out.println(obj);
	}
}

class Person{
	public Person(String name,int age){
		
	}
}


4、Constructor類中的方法

1、getConstructors()方法

該方法是獲取該類中所有構造方法,返回Constructor陣列

2、getConstructor()方法和newInstance()方法

該方法時獲取到指定引數的構造方法

public class Demo {
	public static void main(String[] args)throws Exception {
		/*Constructor[] c = Class.forName("java.lang.String").getConstructors();
		for(Constructor con : c){
			System.out.println(con);
		}*/
		method();
	}
	
	public static void method() throws Exception{
		/*
		 * 原始碼:
		 * Constructor<T> getConstructor(Class<?>... parameterTypes)
		 * 
		 * public T newInstance(Object... initargs)
          *throws InstantiationException,
          *              IllegalAccessException,
          *              IllegalArgumentException,
          *              InvocationTargetException
		 * */ 
		
		//第一步:通過Class類物件呼叫getConstructor方法獲取指定引數型別的建構函式
		Constructor c = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
		//第二步:通過Constructor物件呼叫newInstance方法傳入引數獲取構造方法並例項化物件
		String str = (String)c.newInstance(new StringBuffer("abc"));
		System.out.println(str.charAt(2)); 
	}
}

3、getConstructor(Class<?>... parameterTypes)方法

該方法時獲取到多個引數的建構函式

public class ClassDemo{
	
	public static void main(String[] args)throws Exception {
		//第一步:獲取到相應Class類物件
		Class cla = Class.forName("cn.itcast.Class.Person");
		//第二步:設定引數陣列
		Class[] clas = new Class[]{double.class,int.class};
		//第三步:獲取Constructor物件
		Constructor con = cla.getConstructor(clas);
		//第四步:設定引數陣列
		Object[] objs = new Object[]{3.1415,2};
		//第五步:生成例項物件
		Object obj = con.newInstance(objs);
		//第六步:列印
		System.out.println(obj);
	}
}

class Person{
	private double d;
	private int i;
	public Person(double d,int i){
		this.d = d;
		this.i = i;
	}
}



5、Field類

1、Field類原始碼:public final class reflect extends AccessibleObject implements Member{.....}

2、Field類屬於java.lang.reflect包

3、Field類不能夠被繼承,不是泛型類,是AccessibleObject類的子類

六種方法:

一、getFields()方法:public Field[] getFields()throws SecurityException {…}

功能:獲取類中public修飾的成員欄位

二、getDeclaredFields()方法:public Field[] getDeclaredFields()throws SecurityException {…}

功能:獲取類中所有修飾符的成員欄位

三、getField(String name)方法:public Field getField(String name)throws NoSuchFieldException,SecurityException {…}

功能:根據給定的欄位名獲取類中public修飾的該欄位物件

四、getDeclaredField(String name)方法:public Field getDeclaredField(String name)throws NoSuchFieldException,SecurityException {…}

功能:根絕給定的欄位名獲取類中所有修飾的該欄位物件

五、set(Object obj, Object value)方法:public void set(Object obj, Object value)throws IllegalArgumentException,IllegalAccessException{…};

功能:設定該欄位物件與Field關聯的值

六、get(Object obj)方法:public Object get(Object obj)throws IllegalArgumentException,IllegalAccessException{…};

功能:獲取該欄位物件與Filed相關聯的值

		/*以下是獲取屬性*/
		Class cla_2 = Class.forName("cn.itcast.ly.Person");
		/*只能訪問public修飾的
		Field fie = cla_2.getField("name");
		fie.set(obj,"liuyang");
		Object str = fie.get(obj);
		System.out.println((String)str);*/
		Field fie = cla_2.getDeclaredField("name");
		fie.setAccessible(true);
		fie.set(obj, "liuyang");
		Object str = fie.get(obj);
		System.out.println((String)str);
		
	}
}

class Person{
	private String name;
	public Person(String name,int age){
		
	}
	public static String method(String name,int age){
		return name;
	}
}


操作非公有欄位的步驟:

1、首先呼叫getDeclaredField(String name)方法獲取指定的欄位物件

Filed filed = Class.forName("java.lang.String").getDeclaredField("abc");

2、在取消對反射的物件進行許可權檢查的機制:

field.setAccessible(true);

6、Method方法

1、Method方法原始碼:public final class Method extends AccessibleObject implements …{…}

2、Field類屬於java.lang.reflect包

3、Field類不能夠被繼承,不是泛型類,是AccessibleObject類的子類

五種方法:

一、getMethods()方法:public Field[] getFields()throws SecurityException {…}

功能:獲取類中public修飾的成員欄位

二、getDeclaredMethods()方法:public Field[] getDeclaredFields()throws SecurityException {…}

功能:獲取類中所有修飾符的成員欄位

三、getMethod(String name,Class<?>…parameterTypes)方法:public Field getField(String name)throws NoSuchFieldException,SecurityException {…}

功能:根據給定的欄位名和引數列表獲取類中public修飾的該欄位物件(如無引數則為null)

四、getDeclaredMethod(String name,Class<?>…parameterTypes)方法:public Field getDeclaredField(String name) throws NoSuchFieldException,SecurityException {…}

功能:根據給定的欄位名和引數列表獲取類中所有修飾的該欄位物件(如無引數則為null)

五、invoke(Object obj, Object... args)方法:public Object invoke(Object obj, Object... args)throws …;

功能:獲取指定的方法。引數列表中的第一個obj代表的是呼叫該方法的物件,

		/*以下是獲取方法的結果*/
		Class cla_1 = Class.forName("cn.itcast.ly.Person");
		Class[] clas_1 = new Class[]{String.class,int.class};
		Method met = cla_1.getMethod("method", clas_1);
		Object[] obj_1 = new Object[]{"haha",12};
		//返回方法的結果
		Object obj_2 = met.invoke(obj,obj_1);
		System.out.println(obj_2);
	}
}

class Person{
	public Person(String name,int age){
		
	}
	public static String method(String name,int age){
		return name;
	}
}


操作非公有欄位的步驟:

1、首先呼叫getDeclaredMethod(String name)方法獲取指定的欄位物件

Method method = Class.forName("java.lang.String").getDeclaredMethod("abc");

2、在取消對反射的物件進行許可權檢查的機制:

field.setAccessible(true);

呼叫靜態方法:invoke方法第一個引數設為null即可