黑马程序员-javaBean内省 泛型 类加载器 动态代理

时间:2023-02-12 09:21:54
---------------------- 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;
}
}

黑马程序员-javaBean内省 泛型 类加载器 动态代理黑马程序员-javaBean内省 泛型 类加载器 动态代理
 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()方法即可。

黑马程序员-javaBean内省 泛型 类加载器 动态代理黑马程序员-javaBean内省 泛型 类加载器 动态代理
 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];

泛型的通配符扩展应用

黑马程序员-javaBean内省 泛型 类加载器 动态代理黑马程序员-javaBean内省 泛型 类加载器 动态代理
 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>();平级的,所以错误。

泛型集合类的综合案例

黑马程序员-javaBean内省 泛型 类加载器 动态代理黑马程序员-javaBean内省 泛型 类加载器 动态代理
 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){}

}

通过反射获得泛型的实际类型参数

黑马程序员-javaBean内省 泛型 类加载器 动态代理黑马程序员-javaBean内省 泛型 类加载器 动态代理
 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虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。

黑马程序员-javaBean内省 泛型 类加载器 动态代理黑马程序员-javaBean内省 泛型 类加载器 动态代理
 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

类加载器之间的父子关系和管辖范围图

 黑马程序员-javaBean内省 泛型 类加载器 动态代理

类加载器的委托机制

当java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

 首先当前线程的类加载器去加载线程中的第一个类。

 如果类A中引用了类B,java虚拟机将使用加载类A的类装载器来加载类B

每个类加载器加载类时,又先委托给其上级类加载器。 

编写自己的类加载器

   1,必须继承一个抽象类ClassLoader

    2,复写findClass

代理

  代理设计 :一个操作的接口有两个子类,其中一个是真实主题实现类,另外一个是代理实现类。代理实现类要完成比真实主题实现类更多的内容,而且

本身还需要处理一些与业务有关的程序代码

   要为已存在的多个具有相同的接口的目标类的各个方法增加一些系统功能,例如,异常处理,日志,计算方法的运行时间,事物处理,等等。
 class X{         void sayHello(){               syso :hello        } } XProxy{       void sayHello(){                 starttime                    X.sayHello();                 endtime      } }   代理 类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能代码。 黑马程序员-javaBean内省 泛型 类加载器 动态代理 如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类,还是代理类,这样以后很容易切换,譬如 ,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。 AOP面向方面编程 黑马程序员-javaBean内省 泛型 类加载器 动态代理 动态代理技术       要为系统中的各种借口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情,写成百上千代理类,太累了。          jvm可以再运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态类。      jvm生成的动态类必须实现一个或多个接口,所以jvm生成动态类只能用作具有相同接口的目标类的代理。    CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理,那么可以用   CGLIB库。     代理类的各种方法中通常除了要调用目标的相应方法和对外返回目标返回结果外,还可以在代理方法中的如下四个位置加上系统功能代码:             1,在调用目标方法之前             2,在调用目标方法之后。             3,在调用目标方法前后             4,在处理目标方法异常的catch块中。 黑马程序员-javaBean内省 泛型 类加载器 动态代理 创建动态类及查看其方法列表
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) ;
}
};