黑馬程序員-java基礎加強-反射的深入講解

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

透徹分析反射的基礎_Class類

Class類
1、定義
java程序中的各個java類也屬於同一類事物,而描述這類事物的Java類就是
   Class。(此Class類中可以描述java中所有類的屬性,如,他們都有類名、都有方法、都有屬性、都有所繼承的類、所實現的接口、
   都有所屬的包等等,這些都是他們共有的屬性,所以可以用一個類來統一進行描述)。
2、Class的每一個實例對象,代表一份字節碼即類在內存中的二進制表示。
3、與class的區別
Class是一個類名,描述一類事物;而class是一個類文件的後綴名,表示文件的類型,表示是一個類文件。
4、創建Class實例對象的三種方法
以類Date爲例
a、類名.class
  Class c=Date.class;
b、對象.getClass();
Class c2=new Date().getClass();
C、Class.forName("類名")
Class c3=Class.forName("java.util.Data");
此方法得到的字節碼可以分爲兩種情況:第一,當此字節碼在內存中時,則直接返回此字節碼即可;
第二,當此字節碼不在內存中時,則用類加載器先將此字節碼加載進內存,緩存在jvm中,然後再返回此字節碼。
緩存在jvm中,這樣以後再用到此字節碼的時候就不用再加載了,直接用即可。
5、九中基本數據類型的字節碼
boolean->boolean.class, byte->byte.class, char->char.class, short->short.class, int->int.class,
long->long.class,  float->float.class,  double->double.class,  void->void.class 
這九種基本數據類型的字節碼也都是Class類的實例對象。
6、Class類中的常用方法

例子:

package cn.itcast.day1;

    public class ReflectTest {
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		String s1=new String();
		Class c1=String.class;
		Class c2=s1.getClass();
		Class c3=Class.forName("java.lang.String");
		System.out.println(c2);//打印結果爲class java.lang.String
		System.out.println(c1==c2);//結果爲true
		System.out.println(c1==c3);//結果爲true
		//以下是方法的使用
		//1、Class.isPrimitive()返回此字節碼是不是基本數據類型的字節碼
		System.out.println(c1.isPrimitive());//結果爲false                    
		System.out.println(int.class.isPrimitive());//結果爲true
		//2、返回此字節碼是否是數組類型的字節碼
		System.out.println(int[].class.isArray());//結果爲true
		//3、判斷
		System.out.println(int.class==Integer.class);//結果爲false
		//每個基本數據類型的字節碼都與它對應的引用數據類型.TYPE相等
		System.out.println(int.class==Integer.TYPE);//結果爲true
	}
}
總之,在源程序中出現的類型,都有各自的Class實例對象,例如:int[],void,int
-------------------------------------------------------------------------
理解反射的概念
1、概念
反射就是將java類中的各個成分映射成相應的java類。
類中的變量,方法,構造函數,包等等信息,就是用相應類的實例對象來表示的,他們是Field,
Method,Constructor,Package等等Method的每一個實例對象,就代表一個類中具體的方法。
---------------------------------------------------------------------------
19.構造方法的反射應用
1、構造方法對應的類爲Constructor
2、得到類中所有的構造方法,利用方法getConstructors()
Constructor[] constructors=String.class.getConstructors();
得到類中的某一個構造方法,利用方法getConstructor(對應的構造方法需要的參數類型的字節碼)
Constructor constructor=String.class.getConstructor(對應的構造方法需要的參數類型的字節碼);
3、通過反射來創建對象的過程如下:
a、得到類的字節碼
b、利用類的字節碼調用方法getConstructor(構造方法需要的參數類型的字節碼)來得到具體的要
  用到的構造方法,即得到Constructor的實例對象
c、通過得到的Constructor的實例對象再調用方法newInstance(創建對象時要傳入的參數),來創建此類的對象。
即爲:Class -> Constructor->創建對象
注意上面兩處傳入的參數類型是一致的。
例子:
   package cn.itcast.day1;
    import java.lang.reflect.Constructor;
	/**
	 *需求:利用反射創建一個對象String s=new String(new StringBuffer("abc"));
	 * */
    public class ConstructorTest {
	public static void main(String[] args)throws Exception {
		// TODO Auto-generated method stub
		//第一步:得到類的字節碼
		Class cs=String.class;
		/*第二步:通過字節碼得到想要的構造方法;
		注意此步驟中,必須寫入構造方法中所要傳入的變量類型的字節碼*/
		Constructor constructor=cs.getConstructor(StringBuffer.class);
		/*第三步:得到相應的構造方法之後,創建想要的類的對象;
		    注意此步驟中,必須寫上(String)類型轉換,因爲編譯器並不知道
		    你所創建的對象的類型,它只是檢查語法是否正確;
		  調用newInstance方法時必須傳入變量的具體值*/
		String s=(String)constructor.newInstance(new StringBuffer("abc"));
		//建立好了String類型的對象之後,則可以使用對象所有的方法。
		System.out.println(s.charAt(2));//結果爲c
	}
}
4、Class.newInstance()
Class.newInstance()爲無參的構造方法,此方法即爲Class->創建對象.比以上方法減少一步
若需求爲:利用反射實現String s=new String();
則可以寫成:String s=String.class.newInstance();
實現原理:
該方法內部先得到默認的構造方法,然後利用該構造方法創建實例對象
該方法內部用到了緩存機制來保存默認構造方法的實例對象,這樣以後可以直接使用了。
----------------------------------------------------------------------------
成員變量的反射
1、成員變量對應的類爲Field類。此類的對象,代表某一個類中的一個成員變量即某一個類中的某一個字段
2、通過反射得到某一個類得對象中的某一個字段的值
步驟如下:即爲:類對象->Class->Field->get(對象)(即得到此對象上次字段的值)
對於字段是公有的:
a、得到類的字節碼
b、通過方法getField(字段的字符串形式)得到類中的某個字段
c、通過得到的字段來調用方法get(對象)來得到此類的某一個對象的此字段的值。
對於字段是私有的:
a、得到類的字節碼
b、通過方法getDeclaredField(字段的字符串形式)來得到類中的私有的字段(即此字段可以被看見了)
注意,不管是私有的還是公有的字段,此方法都適用。
c、通過調用方法setAccessible(true)來實現能夠拿到此變量的值。
d、通過得到的字段來調用方法get(對象)來得到此類的某一個對象的此字段的值。
以上這種方法爲暴力反射。
3、 暴力反射 
暴力反射就是將某個類私有字段的訪問檢查去掉
 例如Person類中有一個私有的age字段,如果要反射出這個字段,則需要調用getDeclaredField(),
 如果使用getField則會拋NOSuchFieldException未找到字段異常,
 如果調用該字段的get或者set方法會拋IllegalAccessException非法的訪問異常,
我們可以通過該字段的setAccessible(true)方法來告訴編譯器是否進行訪問檢查.true就代表不進行訪問檢查.
例子:
     package cn.itcast.day1;
     import java.lang.reflect.Field;
	 public class FieldTest {
	  public static void main(String[] args)throws Exception{
		//FieldCode fc=new FieldCode(3,4);
		//通過反射來創建類的對象
		FieldCode fc=FieldCode.class.getConstructor(int.class,int.class).newInstance(4,5);
		
		//得到此類的字節碼
		Class c=fc.getClass();
		//通過字節碼來調用函數getField(String name)方法來得到類的某個字段
		Field fieldY=c.getField("y");
		//通過調用方法get(對象)來得到此對象對應的此字段的值
		System.out.println(fieldY.get(fc));
		
		//通過調用方法getDeclaredField(String name)來得到私有成員變量的字段
		Field fieldX=c.getDeclaredField("x");
		//通過方法setAccessible(true)來使此私有字段可訪問
		fieldX.setAccessible(true);
		//通過調用方法get(對象)來取得對應的值
		System.out.println(fieldX.get(fc));				
	}
}
class FieldCode{
	private int x;
	public int y;
	public FieldCode(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}	
}
-----------------------------------------------------------------------------
成員變量反射的綜合案例
需求:利用反射將一個類中所有的字符串字段中的b改爲a。
步驟:
1、得到一個想要進行操作的對象。
2、得到此對象的所有的字段,利用方法getFields()
3、遍歷這些字段,並判斷這些字段哪些屬於字符串
4、利用方法replace(old,new)來完成替換功能。
注意要想通過反射來得到字段,則必須明確是要操作哪個對象,因爲不同的對象其字段的值也不同。
例子:

package cn.itcast.day1;
import java.lang.reflect.Field;
public class FieldTest {
	public static void main(String[] args)throws Exception{
		//將類FieldCode中的所有字符串字段中的b替換成a
		//1、得到此類的對象
		FieldCode f=FieldCode.class.getConstructor(int.class,int.class).
				             newInstance(5,6);
		//2、的到此類中的所有的字段
		Field[] fields=f.getClass().getFields();
		//3、遍歷此類的所有字段
		for (Field field : fields) {
			if (field.getType()==String.class) {
				//4.得到此字段的值
				String oldStr=(String)field.get(f);
				//5.替換
				String newStr=oldStr.replace('b', 'a');
				//6、將替換後的值給此對象,讓此對象知道
				field.set(f, newStr);	
			}	
		}
		System.out.println(f);	
	}
}
class FieldCode{
	private int x;
	public int y;
	public String str1="abcde";
	public String str2="basketball";
	public String str3="itcast";
	public FieldCode(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}	
	public String toString(){
		return str1+","+str2+","+str3;
	}
}
-----------------------------------------------------------------------------
成員方法的反射
1、成員方法對應的類爲Method,此類對象是爲類中的對象而不是具體對象的方法。
2、需求:利用反射來達到str.charAt(1)的效果
步驟:
a、通過調用字節碼中的方法getMethod(方法名字符串,此方法的參數類型的字節碼)
來獲取類中對應的方法。方法的參數類型字節碼主要是用來區分重載函數的。
b、通過方法invoke(對象,參數值)來決定此方法作用的對象。
例子:
           package cn.itcast.day1;
           import java.lang.reflect.Method;
           public class MethodTest {
			public static void main(String[] args)throws Exception {
				// TODO Auto-generated method stub
				//String str=new String("abcd");或者使用以下方式來獲取對象
				String str=String.class.getConstructor(StringBuffer.class).
						newInstance(new StringBuffer("abcd"));
				
				//1、得到類中相應的方法
				Method method1=str.getClass().getMethod("charAt", int.class);
				//2、調用方法對象的方法invoke(對象,參數值)來決定此方法要作用在哪個對象上
				//以及傳入方法中的參數值
				System.out.println(method1.invoke(str, 1));
			}
		}
3、jdk1.4和jdk1.5中invoke()方法的區別
主要區別爲參數列表的形式不同
jdk1.4中invoke()方法的參數形式用的是數組型的
格式:public Object invoke(Object obj,Object[] args)//obj爲此成員方法要作用什麼對象身上,
//數組即爲方法的參數列表值,
如寫成:method1.invoke(str,new Object{1});
jdk1.5中invoke()方法的參數列表運用的是泛型
格式:public Object invoke(Object obj,Object...args)
注意:1、invoke方法是方法對象的方法,即是方法Method類的對象method1上的對象。
 2、invoke(null,參數值)表示此成員方法是靜態的,不用通過對象調用。
-----------------------------------------------------------------------------
對接收數組參數的成員方法進行反射
需求:寫一個程序,這個程序能夠根據用戶提供的類名,去執行該類中的main方法
分析:要想達到根據用戶提供的類名來執行該類中的main方法,則即爲在運行環境中
 用戶來輸入想要運行的類,則此類就傳入到了主類的main函數的參數數組中,
 即以字符串的形式存在了,而調用此類的main函數,要麼通過類名調用,要麼
 通過此類的對象調用,但由於此類已經被封裝成了字符串,所以這兩種都是沒
 辦法用的,所以用反射的形式來完成調用此類的main函數,
 步驟爲:得到此類的字節碼Class->得到相應的main方法Method->main方法作用
 於什麼對象,並指定傳入main方法的參數即調用invoke()。
 注意:用戶傳入的類名是在運行環境中的參數列表中傳入即寫入:cn.itcast.day1.StartClassName
則此類就傳入到了MethodTest類中的main方法參數中。
 例子:
        package cn.itcast.day1;
	import java.lang.reflect.Method;
	public class MethodTest {
	public static void main(String[] args)throws Exception {
		// TODO Auto-generated method stub
		//String str=new String("abcd");或者使用以下方式來獲取對象
		String str=String.class.getConstructor(StringBuffer.class).
				newInstance(new StringBuffer("abcd"));
		//得到類中相應的方法
		Method method1=str.getClass().getMethod("charAt", int.class);
		//調用方法對象的方法invoke(對象,參數值)來決定此方法要作用在哪個對象上
		//以及傳入方法中的參數值
		System.out.println(method1.invoke(str, 1));
		System.out.println("--------------main數組測試------------------");
		//1、得到用戶傳來的類名的字符串形式
		String startclassname=args[0];
		//2、通過反射得到此類的main方法
		Method method=Class.forName(startclassname).getMethod("main",String[].class);
		//3、將此方法作用此什麼對象上,並傳入什麼樣的參數(即調用此方法,並傳入參數)
		method.invoke(null,(Object)new String[]{"123","456","789"});
		//注意,由於main方法中的參數是一個字符串數組型的,那麼該如何爲
		//invoke方法傳遞參數?若傳入的參數爲new String[]{"123","456","789"}),則java會
		//將它進行拆包,當成三個參數傳入main方法的一個參數中,而不是單獨的一個數組,所
		//以會出現:IllegalArgumentException: wrong number of arguments的異常現象,
		//所以解決的辦法有兩種:第一是:method.invoke(null,(Object)new String[]{"123","456","789"});
		//即告訴編譯器,我的這個數組是一個整體,你不要再把我拆包,拆成三個了
		//第二是method.invoke(null,new Object[]{new String[]{"123","456","789"}});
		//即表示,你不是要拆包嗎,我再包裝一層數組,你拆吧,拆開之後是一個數組整體。
	}
}
class StartClassName{
	public static void main(String[] args){
		for (String string : args) {
			System.out.println(string);		
		}	
	}
}
-----------------------------------------------------------------------------
數組與Object的關係及其反射類
1、對於數組:具有相同維數和元素類型的數組屬於同一個類型,即具有相同的Class實例對象。
2、代表數組的Class實例對象的getSuperClass()方法返回的父類爲Object類對應的Class。
3、基本類型的一維數組可以被當做Object類型使用,但不能當做Object[]類型使用。而非
  基本類型的一維數組既可以被當做Object類型使用也可以當做Object[]類型使用。
4、將數組直接打印出來而不是再寫for循環,即利用的是方法
   public static List asList(Object obj),即返回的是List集合
或者方法Arrays.toString(i);
 對於System.out.println(Arrays.asList(s1));//[a, b, c]
  System.out.println(Arrays.asList(i));//[[I@12452e8]
 利用方法public static List asList(Object obj),返回的是List集合
  而List集合中存放的是對象,對於數組S1它裏面的對象爲String,而String是一個
  引用數據類型的,所以直接將此數組中的每個元素分別存入集合中;而i數組中的元素
  類型爲int型的,是基本數據類型,不是引用數據類型,所以它裏面的元素不能直接被當做
  對象來存入集合中,所以把整個數組當做了一個整體,作爲一個對象存入到了集合中。
5、即總結:public static List asList(Object obj)方法使用的是數據類型是引用數據類型
  Arrays.toString(i);方法使用於打印數據類型爲任何數據類型的數組中的元素。
  例子:
package cn.itcast.day1;
import java.util.Arrays;
public class ReflectArrayTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] a1=new int[2];
		int[] a2=new int[3];
		int[][] a3=new int[2][3];
		String[] a4=new String[2];
		System.out.println(a1.getClass()==a2.getClass());//結果爲true
		//System.out.println(a1.getClass()==a3.getClass());//結果爲false
		//System.out.println(a1.getClass()==a4.getClass());//結果爲false
		//得到數組a1的字節碼
		System.out.println(a1.getClass());//結果爲class [I
		//得到字節碼的名字
		System.out.println(a1.getClass().getName());//結果爲[I
		System.out.println("-------第二部分------------------------");
		//結果都爲:java.lang.Object
		System.out.println(a1.getClass().getSuperclass().getName());
		System.out.println(a4.getClass().getSuperclass().getName());
		System.out.println("----------第三部分---------------------");
		//3、注意有下面的等式
		Object obj1=a1;//此式是成立的
		//Object[] obj2=a2//此式是不成立的
		Object obj3=a3;//此式是成立的
		Object obj4=a4;//此式是成立的
		Object[] obj5=a4;//此式是成立的
		Object[] obj6=a3;//此式是成立的	
		System.out.println("-------------第四部分------------------");
		//4、要想直接打印出數組中的元素,則以下方法
		String[] s1=new String[]{"a","b","c"};
		int[] i=new int[]{1,2,3};
		System.out.println(Arrays.asList(s1));//[a, b, c]
		System.out.println(Arrays.asList(i));//[[I@12452e8]
		System.out.println(Arrays.toString(i));//[1,2,3]
		System.out.println(Arrays.toString(s1));//[a,b,c]
	}
}
-----------------------------------------------------------------------------
數組的反射應用
對數組進行反射的類爲Array,主要方法有:Array.getLength(數組名字)
Array.get(數組名稱,角標)(即得到數組中某個角標的元素)
例子:
package cn.itcast.day1;
import java.lang.reflect.Array;
import java.util.Arrays;
public class ReflectArrayTest {
	public static void main(String[] args) {
		int[] i=new int[]{1,2,3};
		System.out.println("-------------第五部分-對數組進行反射操作的類Array------------------");
		printTest("xyz");
		printTest(i);	
	}
	//即對於對象,看是否是數組,是,則拆包並打印每個數組元素;不是,則直接打印此對象。
	private static void printTest(Object obj) {
		// TODO Auto-generated method stub
		//1.得到此對象的字節碼
		Class clazz=obj.getClass();
		if (clazz.isArray()) {
			//得到此數組的長度
			int len=Array.getLength(obj);
			for (int y = 0; y < len; y++) {
				System.out.println(Array.get(obj, y));		
			}		
		} else {
			System.out.println(obj);
		}	
	}
}
-----------------------------------------------------------------------------
ArrayList_HashSet的比較及Hashcode分析
1、ArryaList集合特點:此集合中的元素是有序的,即先進來的元素就放在集合前面,後進來的
元素就放在後面;元素可重複。
2、HashSet集合特點:集合中的元素是無序的,並且是不可重複的。通過實現方法hashcode和方法
equals來達到元素唯一的目的。
3、hashCode方法的作用:
第一:它使用於運用hash值的結構中;
第二:它將集合分成了幾個區域,當存入對象時首先先算出此對象的hash值,看此對象屬於
 哪個區域,並放進相應的位置;當對集合中的元素進行刪除或者比較的時候,直接算出
 所要進行比較或者刪除的元素的hash值,看此hash值屬於哪個區域,直接去這個區域找
 這個元素即可,提高了效率。
第三:保證了存入集合中元素的唯一性。因爲對於存入的元素先算hash值,跟集合中有的元素的
 hash值相等,則再調用equals方法,若equals比較的也是相等,則視爲相同元素,從而不再
 存入此集合,所以保證了集合元素的唯一性。
4、hashcode中算出的hash值可能會導致內存泄露。
因爲在對於hashCode方法算hash值時,注意:當一個對象被存儲進HashSet集合中以後,就不能修改這個對象中的
那些參與計算哈希值的字段了,都則,對象修改以後的哈希值與最初存儲進HashSet集合中的哈希值就不同了。
那麼,當刪除此元素時,由於算出的目前的hash值和存儲進集合中的哈希值不一樣,所以刪除不掉此元素,這樣就
會導致,不用的元素一直存在,釋放不了內存空間,所以導致內存泄露。
例子:
package cn.itcast.day1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class HashCodeTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("------------ArrayList-----------------");
		Collection collections=new ArrayList();
		HashCodeDemo hcd1=new HashCodeDemo(3,3);
		HashCodeDemo hcd2=new HashCodeDemo(5,6);
		HashCodeDemo hcd3=new HashCodeDemo(3,3);
		collections.add(hcd1);
		collections.add(hcd2);
		collections.add(hcd3);
		collections.add(hcd1);
		System.out.println(collections.size());//結果爲4
		
		System.out.println("------------HashCode-----------------");
		Collection collections2=new HashSet();
		HashCodeDemo hcd4=new HashCodeDemo(3,3);
		HashCodeDemo hcd5=new HashCodeDemo(5,6);
		HashCodeDemo hcd6=new HashCodeDemo(3,3);
		collections2.add(hcd4);
		collections2.add(hcd5);
		collections2.add(hcd6);
		collections2.add(hcd4);
		System.out.println(collections2.size());//結果爲2
		//注意此集合的長度,當沒複寫hashCode和equals的方法時結果爲3,因爲hashCode
		//默認的是對象的內存地址值得到的hash值,所以hcd4和hcd6是不同的元素,所以都被
		//加入進去了。
		//改變參與hash值運算的變量的值。 
		hcd4.x=7;
		collections2.remove(hcd4);
		System.out.println(collections2.size());//結果仍爲2,因爲並未去掉。	
	}
}
class HashCodeDemo{
	public int x;
	public int y;
	public HashCodeDemo(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		HashCodeDemo other = (HashCodeDemo) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}
}
-----------------------------------------------------------------------------
框架的概念及用反射技術開發框架的原理
1、框架的概念:
框架即爲實現一個功能,但是這個功能內部調用的類或者其他的事物並不明確具體
是什麼,而是由以後具體用到的時候再具體給出。這就是框架。
2、框架要解決的問題:
第一:我在寫框架時,你這個類可能還未被定義出來,那麼該怎麼調用你這樣的一個類
第二:因爲寫框架的時候並不知道類名,所以,在程序中無法直接new某個類
的實例對象了,那麼該怎麼對此類進行各種操作呢?
3、要想解決以上問題就用反射來做。
步驟:第一,寫一個配置文件,將以後要用到的類,可以寫在配置文件中,用哪個就寫哪個
 這樣就不用再改框架中的代碼了。配置文件創建步驟:工程->new->file->
 文件名稱:config.properties,這樣將配置文件創建在了此工程下。用戶只要在運行
 的時候通過記事本修改配置文件中的信息即可。
 第二:通過流和Properties類將配置文件加載進此工程的目錄下並獲取類名字符串即可。
 第三:通過反射來得到類的字節碼,然後通過Class類中的各種方法來對此
類進行想要操作的動作。

例子:

package cn.itcast.day1;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;
public class ReflectTest3 {
	public static void main(String[] args)throws Exception{
		System.out.println("------------第一步加載進配置文件-----------------");
		//讓輸入流和文件進行相關聯,來讀取這個文件。
		InputStream is=new FileInputStream("config.properties");
		Properties pro=new Properties();
		//將文件加載進此類的目錄中
		pro.load(is);
		is.close();//注意此處是關閉的是用到的系統的底層資源,而不是流。
		System.out.println("------------第二步得到配置文件的信息-----------------");
		//得到此配置文件中的信息
		String className=pro.getProperty("className");
		System.out.println("------------第三步通過反射來創建對象並進行操作-----------------");
		//Collection collections=new ArrayList();以前的做法
		//現在用反射的做法來創建集合對象,由於是無參的構造函數,所以可以
		//直接利用Class.newInstance()來創建對象。
		Collection collections=(Collection)Class.forName(className).newInstance();
		HashCodeDemo hcd1=new HashCodeDemo(3,3);
		HashCodeDemo hcd2=new HashCodeDemo(5,6);
		HashCodeDemo hcd3=new HashCodeDemo(3,3);
		collections.add(hcd1);
		collections.add(hcd2);
		collections.add(hcd3);
		collections.add(hcd1);
		System.out.println(collections.size());//根據配置文件中的集合類型來決定最後的集合長度		
	}
}
-----------------------------------------------------------------------------
用類加載器的方式管理資源和配置文件
每一個框架都有配置文件,而加載配置文件的原理是:框架內部利用類加載器加載的配置文件,所以
配置文件一般都是放在classpath路徑下(因爲類加載器是在加載的類的目錄下加載配置文件的);若
用eclipse開發程序,則配置文件一般放在source目錄下即源文件目錄下或者source子目錄下(即子包),
它會自動的將配置文件加載進classpath的目錄下。
如下:InputStream is=ReflectTest3.class.getClassLoader().getResourceAsStream("具體目錄名");
或者:InputStream is=ReflectTest3.class.getResourceAsStream("相對目錄名或者具體目錄名");
-----------------------------------------------------------------------------     
由內省引出JavaBean的講解
內省的英文字母爲:IntroSpector:檢查、視察
1、定義
JavaBeen是一種特殊的java類,主要用於傳遞數據信息,這樣java類中的方法
主要用於訪問私有的字段,且方法名符合某種命名規則,即必須有以get和set爲前綴的方法
例如:下面的類即爲JavaBeen類,因爲裏面有以set和get爲前綴的方法。
class Person
	{
		private int age;
		public void setAge(int age)
		{
			this.age=age;
		}
		public int getAge()
		{
			return age;
		}
	}
2、JavaBeen可以當做一般的類進行操作,而一般的類不一定可以當做JavaBeen類來進行操作
因爲只有當一般的類中有分別以get和set爲前綴的方法纔可以。
3、JavaBeen的屬性是什麼呢?
JavaBeen的屬性是去掉get和set前綴剩下的那部分,即爲JavaBeen的
屬性,而不是類中的私有成員變量是它的屬性。所以即爲設置和獲取age屬性值。
4、對於獲取的屬性,該如何用?
當得到的屬性名的第二個字母是小寫,而第二個字母是大寫則把第一個字母也小寫,
如:getAge去掉get爲Age->age
當得到的屬性名的第二個字母是大寫,則並不把第一個字母變爲小寫,如:getCPU和setCPU
則屬性名爲CPU
當得到的屬性名的第一個字母是小寫,都是小寫,則這就是屬性名了,不再變大小寫
如:gettime和settime,則屬性名爲time。
5、什麼時候使JavaBeen呢?
如果要在兩個模塊之間傳遞多個信息,可以將這些信息封裝到一個JavaBeen中,這種JavaBeen的
實例對象通常稱之爲值對象(Value Object,簡稱VO),這些信息在類中用私有字段來存儲,如
果讀取或者設置這些字段的值,則需要通過一些相應的方法來訪問。
-----------------------------------------------------------------------------     
對JavaBean的簡單內省操作
1、JDK中提供了對JavaBeen進行操作的一些API,這套API就成爲內省。如果對於私有的x,只是
通過getX方法來訪問,有一定的難度,用內省這套API操作JavaBeen比用普通類的方式更方便。
2、對於類中私有的屬性進行取值
步驟:
第一,通過創建對象PropertyDescriptor來得到對於哪一個對象上的哪一個屬性進行描述;
第二,通過此對象調用方法getReadMethod()來得到getX()(即X屬性的讀方法);
第三,用此方法調用invoke(類名)來說明此方法是作用於哪個對象上並調用此方法。
3、對於類中的私有屬性進行設值
步驟:
第一,通過創建對象PropertyDescriptor來得到對於哪一個對象上的哪一個屬性進行描述;
第二,通過此對象調用方法getWriteMethod()來得到setX()(即X屬性的寫方法);
第三,用此方法調用invoke(類名,要設置的值)來說明此方法是給什麼對象上的此屬性賦值。
例子:
package cn.itcast.day1;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class IntroSpectorTest {
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		 GetSetDemo gsd=new GetSetDemo(4,5);
		System.out.println("---------對x屬性進行讀取值---------------");
		//第一部分:創建PropertyDescriptor對象,傳入的gsd.getClass()表示要被當做JavaBeen類的類
		//說明要進行描述的屬性
		String propertyName="x";
		PropertyDescriptor pts=new PropertyDescriptor(propertyName,gsd.getClass());
		//第二部分:通過此對象調用getReadMethod()來得到對x屬性的讀方法
		Method methodRead=pts.getReadMethod();
		//第三部分:調用invoke(類名),來獲取此屬性的值
		System.out.println(methodRead.invoke(gsd));
		System.out.println("---------對x屬性進行設置值---------------");
		//第一步創建PropertyDescriptor對象,說明要進行描述的屬性
		PropertyDescriptor pts1=new PropertyDescriptor(propertyName,gsd.getClass());
		//第二部分:通過此對象調用getWriteMethod()來得到對x屬性的寫方法
		Method methodWrite=pts.getWriteMethod();
		//第三部分:調用invoke(類名),來設置此屬性的值
		methodWrite.invoke(gsd,7);
		System.out.println(gsd.getX());
	}
}
class GetSetDemo{
	private int x;
	private int y;
	public GetSetDemo(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}	
}
-----------------------------------------------------------------------------  
使用BeanUtils工具包操作JavaBean
對於上面代碼的那麼多的步驟:即得到要操作的屬性->得到對於操作此屬性的各種方法->
運用此方法。BeenUtils工具包將以上這樣複雜的過程裝換成了一步
例如:對於類中私有的屬性進行取值:BeenUtils.getProperty(gsd,"x");
 對於類中的私有屬性進行設值:BeenUtils.setProperty(gsd,"x","7");
 //注意參數是字段名稱和賦的值都是以字符串形式傳入。


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


詳情請查看:http://edu.csdn.net


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