泛型动态代理基础.docx
《泛型动态代理基础.docx》由会员分享,可在线阅读,更多相关《泛型动态代理基础.docx(45页珍藏版)》请在冰点文库上搜索。
泛型动态代理基础
泛型(Generic)—泛形的作用
JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
注意:
泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。
但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
泛形的基本术语,以ArrayList为例:
<>念着typeof
ArrayList中的E称为类型参数变量
ArrayList中的Integer称为实际类型参数
整个称为ArrayList泛型类型
整个BaseDaoParameterizedType/Type
自定义泛形——泛型类和反射泛形
如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:
publicclassGenericDao{
privateTfield1;
publicvoidsave(Tobj){}
publicTgetId(intid){}
}
泛形的典型应用:
BaseDao和反射泛型
Annotation(注解)概述
从JDK5.0开始,Java增加了对元数据(MetaData)的支持,也就是Annotation(注解)。
什么是Annotation,以及注解的作用?
三个基本的Annotation:
@Override:
限定重写父类方法,该注解只能用于方法
@Deprecated:
用于表示某个程序元素(类,方法等)已过时
@SuppressWarnings:
抑制编译器警告.
Annotation其实就是代码里的特殊标记,它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。
在Java技术里注解的典型应用是:
可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
掌握注解技术的要点:
如何自定义注解
如何反射注解,并根据反射的注解信息,决定如何去运行类
自定义Annotation
定义新的Annotation类型使用@interface关键字
声明注解的属性
注解属性的作用:
原来写在配置文件中的信息,可以通过注解的属性进行描述。
Annotation的属性声明方式:
Stringname()或String[]likes();
属性默认值声明方式:
Stringname()default“xxx”;
特殊属性value:
如果注解中有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx")
特殊属性value[];
枚举值之间使用逗号分隔
@MyAnnotation(name="jack",age=30,likes={"唱歌","跳舞"})
JDK的元Annotation
元Annotation指修饰Annotation的Annotation。
JDK中定义了如下元Annotation:
@Retention:
只能用于修饰一个Annotation定义,用于指定该Annotation可以保留的域,@Rentention包含一个RetentionPolicy类型的成员变量,通过这个变量指定域。
RetentionPolicy.CLASS:
编译器将把注解记录在class文件中.当运行Java程序时,JVM不会保留注解.这是默认值
RetentionPolicy.RUNTIME:
编译器将把注释记录在class文件中.当运行Java程序时,JVM会保留注解.程序可以通过反射获取该注释
RetentionPolicy.SOURCE:
编译器直接丢弃这种策略的注释
JDK的元Annotation
@Target:
指定注解用于修饰类的哪个成员.@Target包含了一个名为value,类型为ElementType(JDK6)的成员变量。
@Documented:
用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档。
@Inherited:
被它修饰的Annotation将具有继承性.如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
提取Annotation信息
JDK5.0在java.lang.reflect包下新增了AnnotationElement接口,该接口代表程序中可以接受注释的程序元素
当一个Annotation类型被定义为运行时Annotation后,该注释才是运行时可见,当class文件被载入时保存在class文件中的Annotation才会被虚拟机读取
程序可以调用AnnotationElement对象的如下方法来访问Annotation信息
动态代理(代理类产生代理对象)
明确两个概念:
代理对象存在的价值:
主要用于拦截对真实业务对象的访问。
代理对象有什么方法?
与真实对象相同,只是无业务代码。
现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。
如何编写生成代理对象的类,两个要素:
代理谁
如何生成代理对象
代理谁?
设计一个类变量,以及一个构造函数,记住代理类代理哪个对象。
如何生成代理对象?
(invoke方法)
设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点)
动态代理(JDK提供)
ava提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:
1.生成代理对象使用哪个类加载器
2.生成哪个对象的代理对象,通过接口指定
3.生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。
初学者必须记住的2件事情:
Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
由于invoke方法被调用需要三个参数:
代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。
动态代理应用
在动态代理技术里,由于不管用户调用代理对象的什么方法,都是调用开发人员编写的处理器的invoke方法(这相当于invoke方法拦截到了代理对象的方法调用)。
并且,开发人员通过invoke方法的参数,还可以在拦截的同时,知道用户调用的是什么方法,因此利用这两个特性,就可以实现一些特殊需求,例如:
拦截用户的访问请求,以检查用户是否有访问权限、动态为某个对象添加额外的功能。
c3p0-config.xml
com.mysql.jdbc.Driver
jdbc:
mysql:
///jdbc_demo
root
root
5
10
com.mysql.jdbc.Driver
jdbc:
mysql:
///day17
root
root
5
10
log4j
1泛型
packagecn.itcast.a_generic;
importjava.util.ArrayList;
importjava.util.List;
importorg.junit.Test;
/**
*泛型基本用法
*@authorJie.Yuan
*
*/
publicclassApp{
//运行时期异常
@Test
publicvoidtestGeneric()throwsException{
//集合的声明
Listlist=newArrayList();
list.add("China");
list.add
(1);
//集合的使用
Stringstr=(String)list.get
(1);
}
//使用泛型
@Test
publicvoidtestGeneric2()throwsException{
//声明泛型集合的时候指定元素的类型
Listlist=newArrayList();
list.add("China");
//list.add
(1);//编译时期报错
Stringstr=list.get
(1);
}
/*
*泛型擦除实例
publicvoidsave(Listp){
}
publicvoidsave(Listd){//报错:
与上面方法编译后一样
}
*/
//泛型写法
@Test
publicvoidtestGeneric3()throwsException{
//声明泛型集合,集合两端类型必须一致
List
Listlist1=newArrayList();
Listlist2=newArrayList();
Listlist3=newArrayList();
//错误
//Listlist4=newArrayList();
//错误:
泛型类型必须是引用类型,不能为基本类型
//Listlist5=newArrayList();
}
}
2
packagecn.itcast.a_generic;
importjava.util.ArrayList;
importjava.util.List;
importorg.junit.Test;
/**
*泛型,涉及到一些关键字
*
*Ctrl+shift+R查看当前项目中类
*Ctrl+shift+T查看源码jar包中的类
*@authorJie.Yuan
*
*/
publicclassApp_extends{
/**
*list集合只能处理Double/Float/Integer等类型
*限定元素范围:
元素的类型要继承自Number类(上限)
*@paramlist
*/
publicvoidsave(List
extendsNumber>list){
}
@Test
publicvoidtestGeneric()throwsException{
Listlist_1=newArrayList();
Listlist_2=newArrayList();
Listlist_3=newArrayList();
Listlist_4=newArrayList();
//调用
save(list_1);
save(list_2);
save(list_3);
//save(list_4);
}
}
3
packagecn.itcast.a_generic;
importjava.util.ArrayList;
importjava.util.List;
importorg.junit.Test;
/**
*泛型,涉及到一些关键字
*
*Ctrl+shift+R查看当前项目中类
*Ctrl+shift+T查看源码jar包中的类
*@authorJie.Yuan
*
*/
publicclassApp_super{
/**
*super限定元素范围:
必须是String父类【下限】
*@paramlist
*/
publicvoidsave(List
superString>list){
}
@Test
publicvoidtestGeneric()throwsException{
//调用上面方法,必须传入String的父类
Listlist1=newArrayList();
Listlist2=newArrayList();
Listlist3=newArrayList();
//save(list3);
}
}
4
packagecn.itcast.a_generic;
/**
*抽象的类
*@authorJie.Yuan
*
*@param
*/
publicclassBaseDaoimplementsIBaseDao{
@Override
publicvoidsave(Tt){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidupdate(Tt){
//TODOAuto-generatedmethodstub
}
}
5
packagecn.itcast.a_generic;
publicclassDept{
}
6
packagecn.itcast.a_generic;
importorg.junit.Test;
/**
*泛型方法/泛型类
*@authorJie.Yuan
*
*/
publicclassGenericDemo{
//定义泛型方法
publicTsave(Tt,Kk){
returnnull;
}
publicvoidupdate(Tt){
}
//测试方法
@Test
publicvoidtestMethod()throwsException{
//泛型类:
在创建爱泛型类对象的时候,确定类型
GenericDemodemo=newGenericDemo();
demo.save("test",1);
}
}
7
packagecn.itcast.a_generic;
/**
*泛型接口
*@authorJie.Yuan
*
*@param
*/
publicinterfaceIBaseDao{
voidsave(Tt);
voidupdate(Tt);
}
8
packagecn.itcast.a_generic;
publicclassPerson{
}
9
packagecn.itcast.a_generic;
/**
*具体业务模块
*@authorJie.Yuan
*
*/
publicclassPersonDaoimplementsIBaseDao{
publicvoidsave(Personp){
}
@Override
publicvoidupdate(Persont){
}
}
2反射
1
packagecn.itcast.b_reflect;
publicclassAccount{
privateintid;
privateStringaccountName;
privatedoublemoney;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetAccountName(){
returnaccountName;
}
publicvoidsetAccountName(StringaccountName){
this.accountName=accountName;
}
publicdoublegetMoney(){
returnmoney;
}
publicvoidsetMoney(doublemoney){
this.money=money;
}
}
2
packagecn.itcast.b_reflect;
publicclassAccountDaoextendsBaseDao{
//只需要写父类没有实现的方法(个性化需求)
}
3
packagecn.itcast.b_reflect;
publicclassAdmin{
privateintid;
privateStringuserName;
privateStringpwd;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetUserName(){
returnuserName;
}
publicvoidsetUserName(StringuserName){
this.userName=userName;
}
publicStringgetPwd(){
returnpwd;
}
publicvoidsetPwd(Stringpwd){
this.pwd=pwd;
}
@Override
publicStringtoString(){
return"Admin[id="+id+",pwd="+pwd+",userName="+userName
+"]";
}
}
4
packagecn.itcast.b_reflect;
publicclassAdminDaoextendsBaseDao{
//根据主键查询
}
5
packagecn.itcast.b_reflect;
importorg.junit.Test;
publicclassApp{
@Test
publicvoidtestSave()throwsException{
AdminDaoadminDao=newAdminDao();
Adminadmin=adminDao.findById(8);
System.out.println(admin);
System.out.println(adminDao.getAll());
}
}
6
packagecn.itcast.b_reflect;
importjava.lang.reflect.ParameterizedType;
importjava.lang.reflect.Type;
importjava.sql.SQLException;
importjava.util.List;
importmons.dbutils.handlers.BeanHandler;
importmons.dbutils.handlers.BeanListHandler;
/**
*所有dao的公用的方法,都在这里实现
*@authorJie.Yuan
*
*/
publicclassBaseDao{
//保存当前运行类的参数化类型中的实际的类型
privateClassclazz;
//表名
privateStringtableName;
//构造函数:
1.获取当前运行类的参数化类型;2.获取参数化类型中实际类型的定义(class)
publicBaseDao(){
//this表示当前运行类(AccountDao/AdminDao)
//this.getClass()当前运行类的字节码(AccountDao.class/AdminDao.class)
//this.getClass().getGenericSuperclass();当前运行类的父类,即为BaseDao
//其实就是“参数化类型”,ParameterizedType
Typetyp