1.学习视频:JDBC封装5(直播)—>ORM封装
2.学习内容
1>补充复习自定义注解:
@Target 描述当前这个注解放在哪用
@Retention 1. .java源文件(Source) 2. .class字节码文件(Class) 3.内存中的Class类映射(Runtime)—>反射可以找到(详细见基础下)
@Inherited 表示该注解会被子类继承,注意:仅针对类,成员属性、方法并不受该注释的影响
注解定义完之后,需要元注解来认证 元注解—>为了描述注解的,元注解本身不做事
增强注解的可读性—>见名知意,在查找调用方法时也起关键作用
@Insert @Update @Delete @Select
2>复习接口—>interface 为了定义规则用的
1)在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
2)接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
3)除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
4)接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
补充:(来自直播课程)
public static final 为默认的,可以不写
接口方法 public abstract void test();
String value();//看起来像属性,其实是方法
如果只定义一个方法,最好用value,在方法上面调用注解时,默认就是value,可以省略不写 @Select(value=”select * from bs”)
5)接口与类相似点:
- 一个接口可以有多个方法。- 接口文件保存在 .java 结尾的文件中,文件名使用接口名。- 接口的字节码文件保存在 .class 结尾的文件中。- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
6)接口与类区别:
- 接口不能用于实例化对象。- 接口没有构造方法。- 接口中所有的方法必须是抽象方法。- 接口不能包含成员变量,除了 static 和 final 变量。- 接口不是被类继承了,而是要被类实现。- 接口支持多继承。
7)接口的特性
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 **public abstract**(只能是 public abstract,其他修饰符都会报错)。- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 **public static final** 变量(并且只能是 public,用 private 修饰会报编译错误)。- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
8)抽象类和接口的区别:
- 1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。- 2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 **public static final** 类型的。- 3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。- 4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
注意:JDK1.8版本以后,接口里可以有静态方法和方法体了。
3.代码练习
package orm.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/*** 自定义注解* 用注解来充当一个搬运工的作用* 帮你将数据 信息搬运给另一个人(解析注解那个人)** 如果注解类型不熟悉* 可以类比着接口的结构来学习(记忆)* 属性 public static final* 方法 public abstract 方法();** 注解定义完之后 需要"大佬"来认证 --> 元注解(为了描述注解的 元注解本身不做事)*/@Target(ElementType.METHOD)//-->放在方法上面用@Retention(RetentionPolicy.RUNTIME)//-->1. .java源文件 2. .class字节码文件 3.内存中的Class类映射public @interface Insert {String value();}
package orm.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Delete {String value();}
package orm.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Update {String value();}
package orm.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Select {String value();}
public interface BankDao {//查询多条方法@Select("select * from bs")public List<Bank> selectList();//查询单条方法@Select("select * from bs where bname = #{bname}")public Bank selectOne(String bname);//数据库新增@Insert("insert into bs values(#{bname},#{bpassword},#{bmoney})")public void insert(Bank bank);//数据库删除@Delete("delete from bs where bname = #{bname}")public void delect(String bname);//数据库更新@Update("update bs set bpassword = #{bpassword} , bmoney = #{bmoney} where bname = #{bname}")public void update(Bank bank);}
//设计一个方法 创建一个代理对象 代理对象去代替原来的Dao做事(让SqlSession干活)// 参数 被代理的那个类是谁??? 被代理的这个类需要是一个接口// 返回值 代理对象/*public <T>T getMapper(Class clazz){//想要通过下面方法创建一个代理对象//需要给他提供三个参数//1.类加载器ClassLoaderClassLoader loader = clazz.getClassLoader();//2.加载的类Class[] 通常数组中就只有一个类Class[] interfaces = new Class[]{clazz};//3.具体这个代理对象该做的事情InvocationHandler----具体做事的实现InvocationHandler handler = new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//这个方法是代理做的方法//方法肯定是做原来被代理对象该做的那个事情return null;}};return (T)Proxy.newProxyInstance(loader,interfaces,handler);}*/public <T> T getMapper(Class clazz){// AtmDao.classreturn (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//这个方法就是代理对象做的方法// 代替原来Dao层做的事情//原来的DAO调用SqlSession对象去做事//proxy就是这个代理对象//method被代理的那个方法(要方法上面注解里的Sql)//args被代理的那个方法的参数(存储的是Sql上的那些所需的值)//获取被代理方法上面的所有注解Annotation an = method.getAnnotations()[0];//an是一个注解对象//获取注解类型-->决定一会儿找SqlSession的哪个方法Class type = an.annotationType();//@Insert @Delete @Update @Select//获取该注解里的sqlMethod valueMethod = type.getDeclaredMethod("value");//执行注解对象里是value方法String sql = (String) valueMethod.invoke(an);//对args做一个处理 基础类型 map domain-->没有Object param = args==null?null:args[0];//判断的目的是找寻SqlSession方法时判断重载的(具体执行哪个方法)//根据type注解类型判断调用的方法if(type == Insert.class){SqlSession.this.insert(sql,param);}else if(type == Delete.class){SqlSession.this.delete(sql,param);}else if(type ==Update.class){SqlSession.this.update(sql,param);}else if(type == Select.class){//根据注解名字无法确定单条 多条//解析method方法的返回值//获取method返回值类型Class methodReturnTypeClass = method.getReturnType();if(methodReturnTypeClass==List.class) {//多条//解析methodReturnTypeClass中的泛型类//获取的是方法返回值的具体类型(java.util.List<domain.Atm>)Type returnType = method.getGenericReturnType();//将returnType还原成可以被操作的 -->Type中为父类,需要向下转型ParameterizedTypeImpl realReturnType = (ParameterizedTypeImpl) returnType;//操作返回值类型中的泛型类-->获取的是泛型类Type[] patternTypes = realReturnType.getActualTypeArguments();//获取数组中的第一个domain.BankType patternType = patternTypes[0];//强制转换为ClassClass patternClass = (Class) patternType;return SqlSession.this.selectList(sql,param,patternClass);}else {//单条return SqlSession.this.selectOne(sql, param, methodReturnTypeClass);}}return null;}});
总结:
这是最后一节ORM封装直播课程,但这并不意味着对于JDBC和ORM的封装学习和复习就此停止,在接下来的一段时间内,我打算在看一遍关于封装的回放,温故而知新嘛hhh,这是一个查缺补漏的过程,在理解思路以及设计思想的基础上,去自己尝试封装编码。
通过这次的封装,在原来Dao上面的JDBC连接数据库的方法,用反射、接口、注解等方式,解决了增删改查方法中的冗余,提高了性能等各方面,思想很重要,知识是永远学不完的,很多方法虽然不知道,但最关键的还是自己的理解程度以及设计方法时能否想到用什么样的方式或是下一步应该做什么,所以思想养成很重要。除此之外,JavaSE基础知识也很重要,封装里面都是基础讲过的内容,嗯,我要补基础了
