黑馬程序員-javaBean內省 泛型 類加載器 動態代理

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

1,由內省引出的 javaBean講解

        內省→IntroSpector(檢查,視察,瞭解內部的細節)→對JavaBean操作→是一個特殊的java類,方法的名稱符合某種約定的規則的java類。 

         這種java類中的方法用於訪問私有的字段,且方法名符合某種命名規則。

       從方法得到屬性-->如果第二個字母是小寫,則把第一個字符變成小寫的

               gettime--time             setTime---time          getCPU--CPU

     總之,一個類被當做javaBean使用時,javaBean的屬性是根據方法名推斷出來的,它根本看不到java類內部的成員變量。

  一個符合javaBean特點的類可以當做普通類一樣使用,但把它當做javaBean用肯定需要帶來一些額外的好處,我們纔會去了解和應用javaBean

    javaEE開發中,經常用到javaBean。很多環境就要求按JavaBean方式進行操作

            如果要在兩個模塊之間傳遞多個信息,可以將這些信息封裝到一個JavaBean中,這種JavaBean的實例對象通常稱爲值對象(Value  Object,簡稱VO)。

    jdk中提供了一些api,這套內省就稱爲內省。

        內省的綜合案例。
package com.itcast.zhang;

public class ReflectPoint {
	private int x;// 私有成員變量
	public int y;// 共有成員變量
	// 共有成員變量str1;str2;str3;
	public String str1 = "ball";
	public String str2 = "baseketball";
	public String str3 = "itcast";

	/**
	 * 得到x
	 * 
	 * @return
	 */
	public int getX() {
		return x;
	}

	/**
	 * 設置x
	 * 
	 * @param x
	 */
	public void setX(int x) {
		this.x = x;
	}

	/*
	 * 得到y
	 */
	public int getY() {
		return y;
	}

	/**
	 * 設置y
	 * 
	 * @param y
	 */
	public void setY(int y) {
		this.y = y;
	}

	/**
	 * 構造方法
	 * 
	 * @param x
	 * @param y
	 */
	public ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}

	/**
	 * 重寫hashCode方法
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}

	/**
	 * 重寫equas方法
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ReflectPoint other = (ReflectPoint) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}

	/**
	 * 重寫toString方法
	 */
	@Override
	public String toString() {
		return str1 + ":" + str2 + ":" + str3;
	}
}

 1 package com.itcast.zhang;
 3 import java.beans.IntrospectionException;
 4 import java.beans.PropertyDescriptor;
 5 import java.lang.reflect.InvocationTargetException;
 6 import java.lang.reflect.Method;
 7 
 8 public class IntroSpectorTest {
 9 
10     /**
11      * @param args
12      * @throws IntrospectionException
13      * @throws InvocationTargetException
14      * @throws IllegalAccessException
15      * @throws IllegalArgumentException
16      */
17     public static void main(String[] args) throws IntrospectionException,
18             IllegalArgumentException, IllegalAccessException,
19             InvocationTargetException {
20         // TODO Auto-generated method stub
21         ReflectPoint pt1 = new ReflectPoint(3, 4);//實例對象
22         String propertyName = "x";//屬性名
23         PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1
24                 .getClass());//屬性描述符,看做javaBean
25         Method methodGetx = pd.getReadMethod();//得到讀的方法
26         Object retVal = methodGetx.invoke(pt1);//調用,讀方法沒有參數
27         System.out.println(retVal);
28         Method methodSetx = pd.getWriteMethod();//得到設置方法
29         methodSetx.invoke(pt1, 7);//對象調用
30         System.out.println(pt1.getX());//原來方式進行輸出輸出
31     }
32 
33 }
 
   直接new 一個PropertyDescription (屬性描述符)類的對象方法讓大家瞭解到JavaBean的價值,先用一段代碼讀取JavaBean的屬性,然後用一段代碼設置JavaBean的屬性。

   採用遍歷BeanInfo的所有屬性方式來查找和設置某個RefectPoint對象的x屬性。在程序中把一個類當做JavaBean來看,就是調用IntroSpectro.getBeanInfo方法,得到的BeanInfo對象封裝了把這個類當做JavaBean的結果信息。但是這種方法寫起來比較麻煩,知道有這種方法就好。

 
package com.itcast.zhang;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class IntroSpectorTest {

	/**
	 * @param args
	 * @throws IntrospectionException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public static void main(String[] args) throws IntrospectionException,
			IllegalArgumentException, IllegalAccessException,
			InvocationTargetException {
		// TODO Auto-generated method stub
		ReflectPoint pt1 = new ReflectPoint(3, 4);
		String propertyName = "x";
		Object retVal = getProperty(pt1, propertyName);
		System.out.println(retVal);
		Object value = 7;
		setProperties(pt1, propertyName, value);
		System.out.println(pt1.getX());
	}

	/**
	 * 設置屬性名的值
	 * 
	 * @param pt1
	 * @param propertyName
	 * @param value
	 * @throws IntrospectionException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private static void setProperties(Object pt1, String propertyName,
			Object value) throws IntrospectionException,
			IllegalAccessException, InvocationTargetException {
		// new 一個PropertyDescription
		// (屬性描述符)類的對象方法,裏面有兩個參數,第一個是屬性名,第二個是對象的字節碼對文件,把某一個類當做javaBean來看可以操作這個類的屬性
		PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1
				.getClass());
		Method methodSetx = pd2.getWriteMethod();// 得到寫的方法。
		methodSetx.invoke(pt1, value);// 調用 傳入value
	}

	/**
	 * 得到屬性名
	 * 
	 * @param pt1
	 *            對象
	 * @param propertyName屬性名
	 * @return
	 * @throws IntrospectionException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private static Object getProperty(Object pt1, String propertyName)
			throws IntrospectionException, IllegalAccessException,
			InvocationTargetException {

		PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1
				.getClass());
		Method methodGetx = pd.getReadMethod();
		Object retVal = methodGetx.invoke(pt1);

		// 麻煩的方式 這中方式用的不太多,只是爲了提高編碼能力而寫
		// 採用遍歷BeanInfo的多有屬性方式來查找和設置某個RefectPoint對象的x屬性。在程序中,
		// 把一個類當做JavaBean開看,就是調用了IntroSpector.getBeanInfo方法,得到BeanInfo對象封裝了把這個類當作javaBean看的結果信息
		/*
		 * BeanInfo beaninfo = Introspector.getBeanInfo(pt1.getClass());
		 * PropertyDescriptor[] pds = beaninfo.getPropertyDescriptors(); Object
		 * retVal = null; for (PropertyDescriptor pd : pds) { if
		 * (pd.getName().equals(propertyName)) { Method methodGetx =
		 * pd.getReadMethod(); retVal = methodGetx.invoke(pt1); break; } }
		 */
		return retVal;
	}

}
關於內省的總結:
內省(IntroSpector)是Java 語言對 Bean 類屬性、事件的一種缺省處理方法。例如類 A 中有屬性 name, 那我們可以通過 getName,setName 來得到其值或者設置新的值。通過 getName/setName 來訪問 name 屬性,這就是默認的規則。 Java 中提供了一套 API 用來訪問某個屬性的 getter/setter 方法,通過這些 API 可以使你不需要了解這個規則(但你最好還是要搞清楚),這些 API 存放於包 java.beans 中,一般的做法是通過類 Introspector 的 getBeanInfo方法 來獲取某個對象的 BeanInfo 信息,然後通過 BeanInfo 來獲取屬性的描述器(PropertyDescriptor),通過這個屬性描述器就可以獲取某個屬性對應的 getter/setter 方法,然後我們就可以通過反射機制來調用這些方法。
 2,泛型
   泛型的加入,是集合在編譯階段,只能添加規定的元素類型。看下面的小例子。
package com.itcast.zhang;

 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 
 public class Test {
     public static void main(String[] args) throws Exception,
             NoSuchMethodException {
    	 //定義一個集合
         ArrayList<String> collection1 = new ArrayList<String>();
         collection1.add("abc");
         //collection1.add(1);這裏編譯錯誤,只能添加固定的類型
         //根據反射 得到構造函數的對象,這裏通過泛型也可以避免強制類型轉換
         Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);
         //這裏也避免了類型轉換的苦惱
         String str2 = constructor1.newInstance(new StringBuffer("abc"));
         System.out.println(str2.charAt(2));
 
     }
 }

package com.itcast.zhang;

import java.lang.reflect.Constructor;
import java.util.ArrayList;

import java.util.ArrayList;

public class Test {
	public static void main(String[] args) { // 已經參數化的類型。
		//定義兩個集合
		ArrayList<String> collection1 = new ArrayList<String>();
		ArrayList<Integer> collection2 = new ArrayList<Integer>();
	//通過比較兩個對象的字節碼,打印是true;
		System.out.println(collection1.getClass() == collection2.getClass());
	}
}

打印true

泛型是提供給java編譯器使用的,可以限定集合中的輸入類型,讓編譯器擋住源程序中的非法輸入,編譯器編譯類型說明的集合時會去掉“類型”信息,使程序運行效率不受影響,對於參數化的泛型類型,getClass()方法的返回值和原始類型完全一樣。由於編譯生成的字節碼會去掉泛型的類型信息,只要能跳過編譯器,就可以往某個泛型集合中加入其它類型的數據,例如,用反射得到集合,再調用add()方法即可。

 1 import java.lang.reflect.InvocationTargetException;
 2 import java.util.ArrayList;
 3 
 4 
 5 public class Test2 {
 6    public static void main(String[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
 7        //已經參數化的類型。
 8      ArrayList<String> collection1=new ArrayList<String>();
 9      ArrayList<Integer> collection2=new ArrayList<Integer>();
10      System.out.println(collection1.getClass()==collection2.getClass());
11     // 編譯錯誤 collection2.add("abc");
12      collection2.getClass().getMethod("add",Object.class).invoke(collection2, "abc");//用反射得到集合,再調用add()方法即可跳過編譯階段
13      System.out.println(collection2.get(0));//打印看結果
14    }
15 }
View Code

打印 abc       --泛型是給編譯器看的
泛型的術語:

整個稱爲ArrayList<E>泛型類型

ArrayList<Integer>稱爲參數化的類型。

ArrayList<Integer>中的Integer稱爲類型參數的實例或實際類型參數

ArrayList<Integer>中的<>念着type of

ArrayList稱爲原始類型。

參數化類型與原始類型的兼容性:

 參數化類型可以引用一個原始類型的對象,編譯器報告警告,例如,

 Collection<String> c=new Vector();

原始類型可以引用一個參數化類型的對象,編譯器報告警告

 Collection c=new Vector<String>();

參數化類型不考慮繼承關係:

 Vector<String> =new Vector<Object>();//錯誤

在創建數組實例時,數組的元素不能使用參數化的類型,例如,下面語句有錯誤:

Vector<Integer> vectorList[]=new Vector<Integeer>[10];

泛型的通配符擴展應用

 1 import java.lang.reflect.InvocationTargetException;
 2 import java.util.ArrayList;
 3 import java.util.Collection;
 4 
 5 public class Test2 {
 6     public static void main(String[] args) throws IllegalArgumentException,
 7             SecurityException, IllegalAccessException,
 8             InvocationTargetException, NoSuchMethodException {
 9         // 已經參數化的類型。
10         ArrayList<String> collection1 = new ArrayList<String>();
11         ArrayList<Integer> collection2 = new ArrayList<Integer>();
12         System.out.println(collection1.getClass() == collection2.getClass());
13         // 編譯錯誤 collection2.add("abc");
14         collection2.getClass().getMethod("add", Object.class).invoke(
15                 collection2, "abc");
16         System.out.println(collection2.get(0));
17         printCollection(collection2);
18     }
19 
20     /**
21      * ?表示任意類型,編譯器不會報錯
22      * 
23      * @param collection
24      */
25     public static void printCollection(Collection<?> collection) {
26         // 編譯錯誤。
27         // ?可以作爲引用變量引用別的類型,但是不能調用與參數有關係的方法
28         // collection.add("abc");
29         collection.size();// 這個方法可以調用,與參數類型無關。
30         for (Object obj : collection) {
31             System.out.println(obj);
32         }
33         // 總結:使用?通配符可以引用其他各種參數化的類型,
34         // ?通配符定義的變量主要作用是引用,可以調用與參數化無關的方法,不能調用與參數化有關的方法。
35 
36     }
37 }
View Code

通配符的限定

 限定通配符的上邊界:

 正確:Vector<?extends Number> x=new Vector<Integer>();--必須是Number以及是Number的子類

 錯誤:Vector<?extends Number>  x=new Vector<String>();

限定通配符的下邊界:

 正確:Vector<?super Integer> x=new Vector<Number>();必須是Integer的父類,或者Integer

錯誤:Vector<?super Integer> x=new Vector<Byte>();平級的,所以錯誤。

泛型集合類的綜合案例

 1 import java.util.HashMap;
 2 import java.util.Map;
 3 import java.util.Set;
 4 
 5 public class Test3 {
 6     public static void main(String[] args) {
 7         HashMap<String, Integer> maps = new HashMap<String, Integer>();//定義一個map集合,鍵是String類型,值是Integer類型
 8         maps.put("xxx", 23);//添加
 9         maps.put("yyy", 22);
10         maps.put("zz", 13);
11         Set<Map.Entry<String, Integer>> enrtyset = maps.entrySet();//Map.Entry<String,Integer>是一個對,包括鍵值
12         for (Map.Entry<String, Integer> entry : enrtyset) {//遍歷打印輸出
13             System.out.println(entry.getKey() + ":" + entry.getValue());
14         }
15     }
16 }
View Code

 定義泛型的類型。

如果類的實例對象中的多處都要用到同意個泛型參數,即這些地方引用的泛型類型要保持同一個實際類型時,這時候就要採用泛型類型的方式進行定義,也就是類級別的泛型,語法格式如下:

   public class Generic<T>{

     pirvate T field;

     public void save(T obj){};

     public T getByid(int id){}

}

通過反射獲得泛型的實際類型參數

 1 import java.lang.reflect.Method;
 2 import java.lang.reflect.ParameterizedType;
 3 import java.lang.reflect.Type;
 4 import java.util.Date;
 5 import java.util.Vector;
 6 
 7 /**
 8  * 通過反射獲得泛型的實際類型參數
 9  * 
10  * @author Administrator
11  * 
12  */
13 public class Test4 {
14     public static void main(String[] args) throws Exception,
15             NoSuchMethodException {
16         Method applyMethod = Test4.class.getMethod("applyVector", Vector.class);
17         Type[] type = applyMethod.getGenericParameterTypes();// 得到參數類型的數組
18         ParameterizedType ptype = (ParameterizedType) type[0];// ParameterizedType
19                                                                 // 是Type的子類
20         System.out.println(ptype.getRawType());// 得到原始類型 打印Vector
21         System.out.println(ptype.getActualTypeArguments()[0]);// 打印Date
22     }
23      //測試方法
24     public static void applyVector(Vector<Date> v1) {
25 
26     }
27 }
View Code

 類加載器

用到一個類,jvm首先也把這個類的字節碼,加載到內存中來進行處理,通常這個字節碼的原始信息放在硬盤上ClassPath指定的目錄下

 java虛擬機中可以安裝多個類加載器,系統默認三個類加載器,每個類負責加載特定位置的類:

   BootStrap,ExtClassLoader,AppClassLoader

類加載器本身也是Java類,因爲其他是Java類的類加載器本身也要被類加載器加載,顯然必須有第一個類加載器不是java類,這正是BootStrap(不需要被加載嵌套在jvm內核中的)

java虛擬機中的所有類裝載器採用具有父子關係的樹形結構進行組織,在實例化每個類裝載器對象時,需要爲其指定一個父級類裝載器對象或者默認採用系統類裝載器爲其父級類加載。

 1 public class ClassLoaderTest {
 2     public static void main(String[] args) {
 3         // 打印 sun.misc.Launcher$AppClassLoader
 4         System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
 5                 .getName());
 6 
 7         // 報錯 空指針異常
 8         // System.out.println(System.class.getClassLoader().getClass().getName());
 9         System.out.println(System.class.getClassLoader());// 打印null 由
10                                                             // BootStrap加載
11         ClassLoader loader = ClassLoaderTest.class.getClassLoader();//得到一個類的加載器
12         while (loader != null) {
13             System.out.println(loader.getClass().getName());//輸出類加載的名字
14             loader = loader.getParent();//得到父級加載器
15         }
16         System.out.println(loader);
17     }
18 }
View Code

類加載器之間的父子關係和管轄範圍圖

 

類加載器的委託機制

當java虛擬機要加載一個類時,到底派出哪個類加載器去加載呢?

 首先當前線程的類加載器去加載線程中的第一個類。

 如果類A中引用了類B,java虛擬機將使用加載類A的類裝載器來加載類B

每個類加載器加載類時,又先委託給其上級類加載器。 

編寫自己的類加載器

   1,必須繼承一個抽象類ClassLoader

    2,複寫findClass

代理

  代理設計 :一個操作的接口有兩個子類,其中一個是真實主題實現類,另外一個是代理實現類。代理實現類要完成比真實主題實現類更多的內容,而且

本身還需要處理一些與業務有關的程序代碼

   要爲已存在的多個具有相同的接口的目標類的各個方法增加一些系統功能,例如,異常處理,日誌,計算方法的運行時間,事物處理,等等。
 class X{
        void sayHello(){
              syso :hello
       }
}
XProxy{
      void sayHello(){
                starttime
                   X.sayHello();
                endtime
     }
}
 
代理 類的每個方法調用目標類的相同方法,並在調用方法時加上系統功能代碼。
如果採用工廠模式和配置文件的方式進行管理,則不需要修改客戶端程序,在配置文件中配置是使用目標類,還是代理類,這樣以後很容易切換,譬如
,想要日誌功能時就配置代理類,否則配置目標類,這樣,增加系統功能很容易,以後運行一段時間後,又想去掉系統功能也很容易。
AOP面向方面編程
動態代理技術
      要爲系統中的各種藉口的類增加代理功能,那將需要太多的代理類,全部採用靜態代理方式,將是一件非常麻煩的事情,寫成百上千代理類,太累了。
         jvm可以再運行期動態生成出類的字節碼,這種動態生成的類往往被用作代理類,即動態類。
     jvm生成的動態類必須實現一個或多個接口,所以jvm生成動態類只能用作具有相同接口的目標類的代理。
   CGLIB庫可以動態生成一個類的子類,一個類的子類也可以用作該類的代理,所以,如果要爲一個沒有實現接口的類生成動態代理,那麼可以用
  CGLIB庫。
    代理類的各種方法中通常除了要調用目標的相應方法和對外返回目標返回結果外,還可以在代理方法中的如下四個位置加上系統功能代碼:
            1,在調用目標方法之前
            2,在調用目標方法之後。
            3,在調用目標方法前後
            4,在處理目標方法異常的catch塊中。
創建動態類及查看其方法列表
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Collection;

/**
 * 創建動態類及查看其方法列表
 * 
 * @author Administrator
 * 
 */
public class Test1 {
	public static void main(String[] args) {
		Class clazzProxy1 = Proxy.getProxyClass(Collection.class
				.getClassLoader(), Collection.class);
		System.out.println(clazzProxy1.getName());// 打印 $Proxy0
		System.out.println("begin constructo list");
		// 有什麼樣的構造 方法
		Constructor[] constructors = clazzProxy1.getConstructors();
		for (Constructor constructor : constructors) {
			// System.out.println(constructor.getName());
			String name = constructor.getName();
			StringBuilder sb = new StringBuilder(name);// 單線程StrinbBuilder
			sb.append('(');
			Class[] classParams = constructor.getParameterTypes();
			for (Class clazzParam : classParams) {
				sb.append(clazzParam.getName()).append(',');

			}
			if (classParams != null && classParams.length != 0) {
				sb.deleteCharAt(sb.length() - 1);
				sb.append(')');
				System.out.println(sb.toString());
			}
		}
	}
}
 
創建動態類的實例對象
    用反射獲得構造方法
    編寫一個最簡單的InvocationHanlder類
    調用構造方法創建動態類實例對象,並將編寫InvocationHandler類的實例對象傳進去,
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;

/**
 * 創建動態類及查看其方法列表
 * 
 * @author Administrator
 * 
 */
public class Test1 {
	public static void main(String[] args) throws Exception,
			InstantiationException, IllegalAccessException,
			InvocationTargetException {
		Class clazzProxy1 = Proxy.getProxyClass(Collection.class
				.getClassLoader(), Collection.class);
		System.out.println(clazzProxy1.getName());// 打印 $Proxy0
		System.out.println("begin constructo list");
		// 有什麼樣的構造 方法
		Constructor[] constructors = clazzProxy1.getConstructors();
		for (Constructor constructor : constructors) {
			// System.out.println(constructor.getName());
			String name = constructor.getName();
			StringBuilder sb = new StringBuilder(name);// 單線程StrinbBuilder
			sb.append('(');
			Class[] classParams = constructor.getParameterTypes();
			for (Class clazzParam : classParams) {
				sb.append(clazzParam.getName()).append(',');

			}
			if (classParams != null && classParams.length != 0) {
				sb.deleteCharAt(sb.length() - 1);
				sb.append(')');
				System.out.println(sb.toString());
			}
		}
		Constructor constructor1 = clazzProxy1
				.getConstructor(InvocationHandler.class);
		class MyInvocationHander1 implements InvocationHandler {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				return null;
			}

		}
		Collection proxy1 = (Collection) constructor1
				.newInstance(new MyInvocationHander1());
		System.out.println(proxy1);// 打印null;但是對象不是null;
		proxy1.clear();
	}
}

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;

/**
 * 創建動態類及查看其方法列表
 * 
 * @author Administrator
 * 
 */
public class Test1 {
	public static void main(String[] args) throws Exception,
			InstantiationException, IllegalAccessException,
			InvocationTargetException {
		Class clazzProxy1 = Proxy.getProxyClass(Collection.class
				.getClassLoader(), Collection.class);
		System.out.println(clazzProxy1.getName());// 打印 $Proxy0
		System.out.println("begin constructo list");
		// 有什麼樣的構造 方法
		Constructor[] constructors = clazzProxy1.getConstructors();
		for (Constructor constructor : constructors) {
			// System.out.println(constructor.getName());
			String name = constructor.getName();
			StringBuilder sb = new StringBuilder(name);// 單線程StrinbBuilder
			sb.append('(');
			Class[] classParams = constructor.getParameterTypes();
			for (Class clazzParam : classParams) {
				sb.append(clazzParam.getName()).append(',');

			}
			if (classParams != null && classParams.length != 0) {
				sb.deleteCharAt(sb.length() - 1);
				sb.append(')');
				System.out.println(sb.toString());
			}
		}
	/*	Constructor constructor1 = clazzProxy1
				.getConstructor(InvocationHandler.class);
		class MyInvocationHander1 implements InvocationHandler {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				return null;
			}

		}
		Collection proxy1 = (Collection) constructor1
				.newInstance(new MyInvocationHander1());
		System.out.println(proxy1);// 打印null;但是對象不是null;
		proxy1.clear();*/
		//第二種方式
		Constructor constructor1 = clazzProxy1
		.getConstructor(InvocationHandler.class);
		Collection proxy2=(Collection)constructor1.newInstance(new InvocationHandler(){

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				return null;
			}
			
		});
	}
}

讓jvm創建動態類及其實例對象,需要給他提供哪些信息?
        》三個方面:
                 生成的類中有哪些方法,通過讓其實現哪些接口的方式進行告知:
                產生的類字節碼必須有一個關聯的類加載器對象。
                生成的類中的方法的代碼是怎麼樣的,也得由我們提供,把我們的代碼寫在一個約好的接口對象的方法中,把對象傳遞給它,它調用我的方法,
即相當於插入了我的代碼。提供執行代碼的對象就是那個InvocationHander對象,它是在創建動態類的實例對象的構造方法時傳遞進去的。在上面的
InvocationHander的對象的invoke方法中加一點代碼,就可以看到這些代碼被調用運行了。
     用Proxy newInstance方法直接一步就創建出代理對象。
下面是另一種方法Proxy.newProxyInstance方法,直接一步到位

Proxy 提供用於創建動態代理類和實例的靜態方法,它還是由這些方法創建的所有動態代理類的超類。   

import java.lang.reflect.InvocationHandler ;
import java.lang.reflect.Proxy ;
import java.lang.reflect.Method ;
interface Subject{
	public String say(String name,int age) ;	// 定義抽象方法say
}
class RealSubject implements Subject{	// 實現接口
	public String say(String name,int age){
		return "姓名:" + name + ",年齡:" + age ;
	}
};
class MyInvocationHandler implements InvocationHandler{
	private Object obj ;
	public Object bind(Object obj){
		this.obj = obj ;	// 真實主題類 代理的對象
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;
	}
	public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
		Object temp = method.invoke(this.obj,args) ;	// 調用方法
		return temp ;
	}
};
public class DynaProxyDemo{
	public static void main(String args[]){
		Subject sub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;
		String info = sub.say("周珂珂",30) ;
		System.out.println(info) ;
	}
};

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