泛型
什么是泛型,什么时候用,怎么用
泛型是一种安全机制,通常用在集合当中,来限定集合中可以存储的类型,阻止泛型定义之外的类型存入数组
并且避免了强制转换的麻烦
可以自定义泛型类或泛型方法来使代码复用,提高编程效率
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。
可以通过反射在泛型定义为Integer的集合当中存入String类型的元素。
可以通过反射在泛型定义为Integer的集合当中存入String类型的元素。
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型
代理
为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等,
采用工厂模式和配置文件的方式进行管理,在配置文件中配置是使用目标类、还是代理类,很容易切换
动态代理
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
public static Class<?> getProxyClass( ClassLoader loader, Class<?>... interfaces)
例如:动态获取实现了Collection接口的类的代理类,一般使用与目标类相同的类加载器
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
此构造函数需要的参数为一个InvocationHandler对象,InvocationHandler为接口,所以一般使用匿名内部类的形式来创造参数
获取构造函数:
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
生成实例对象:
Collection proxy = (Collection)constructor.newInstance(new InvocationHandler(){
//这是InvocationHandler接口定义的抽象函数,子类必须实现此函数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
public static Object newProxyInstance( ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
举例如下:
Collection proxy = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader, //类加载器
new Object[]{Collection.class}, //要实现的接口
new InvocationHandler(){ //InvocationHandler匿名内部类
ArrayList target = new ArrayList(); //定义目标类
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable{
Object retVel = nethod.invoke(target, args);
return retVel;
}
});
private static Object getProxy(final Object target,final Advice advice) {
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object arg0, Method method, Object[] arg2)
throws Throwable {
advice.beforeMethod(method);;
Object ret = method.invoke(target, arg2);
advice.afterMethod(method);
return ret;
}
});
return proxy;
}
}
interface Advice
{
void beforeMethod(Method method);
void afterMethod(Method method);
}
class MyAdvice implements Advice
{
long bTime;
public void beforeMethod(Method method) {
// TODO Auto-generated method stub
bTime = System.currentTimeMillis();
}
public void afterMethod(Method method) {
// TODO Auto-generated method stub
long eTime = System.currentTimeMillis();
System.out.println(method.getName()+"函数运行时间: "+(eTime-bTime));
}
}
获取动态类
动态类由Proxy类的getProxyClass()函数来获取,参数为获取到的类指定类加载器与需要实现的接口public static Class<?> getProxyClass( ClassLoader loader, Class<?>... interfaces)
例如:动态获取实现了Collection接口的类的代理类,一般使用与目标类相同的类加载器
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
获取动态类的实例对象
动态生成的代理类只有一个带参数的构造函数,所以需要获取此构造函数,然后使用反射创建具体对象此构造函数需要的参数为一个InvocationHandler对象,InvocationHandler为接口,所以一般使用匿名内部类的形式来创造参数
获取构造函数:
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
生成实例对象:
Collection proxy = (Collection)constructor.newInstance(new InvocationHandler(){
//这是InvocationHandler接口定义的抽象函数,子类必须实现此函数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
一步获取动态类对象
通过Proxy的静态方法newProxyInstance()来直接获取一个动态类的对象public static Object newProxyInstance( ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
举例如下:
Collection proxy = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader, //类加载器
new Object[]{Collection.class}, //要实现的接口
new InvocationHandler(){ //InvocationHandler匿名内部类
ArrayList target = new ArrayList(); //定义目标类
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable{
Object retVel = nethod.invoke(target, args);
return retVel;
}
});
Collection proxy = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader, //类加载器
new Object[]{Collection.class}, //要实现的接口
new InvocationHandler(){ //InvocationHandler匿名内部类
ArrayList target = new ArrayList(); //定义目标类
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable{
//添加在目标类的函数执行前执行的功能代码
Object retVel = nethod.invoke(target, args);
//添加在目标类的函数执行后执行的功能代码
return retVel;
}
});
将上面的动态代理改成通用代理类
private static Object getProxy(final Object target,final Advice advice) {
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object arg0, Method method, Object[] arg2)
throws Throwable {
advice.beforeMethod(method);;
Object ret = method.invoke(target, arg2);
advice.afterMethod(method);
return ret;
}
});
return proxy;
}
}
interface Advice
{
void beforeMethod(Method method);
void afterMethod(Method method);
}
class MyAdvice implements Advice
{
long bTime;
public void beforeMethod(Method method) {
// TODO Auto-generated method stub
bTime = System.currentTimeMillis();
}
public void afterMethod(Method method) {
// TODO Auto-generated method stub
long eTime = System.currentTimeMillis();
System.out.println(method.getName()+"函数运行时间: "+(eTime-bTime));
}
}