Java泛型Dao学习笔记:
针对数据库表中的共有字段(比如:id,title,name)。
设计泛型Dao:
public class BaseDao<T> {
private String tableName;
private Class clazz;
//通过反射泛型,得到具体的参数类型
protected BaseDao() {
//得到字节码对象
//Class baseDaoClass = BaseDao.class;这样会报错的,
Class baseDaoClass = this.getClass();
//得到BaseDao的泛型类型
Type type = baseDaoClass.getGenericSuperclass();
//把BaseDao的泛型类型转为ParameterizedTyp参数化类型
ParameterizedType pt = (ParameterizedType) type;
//从参数化类型带得实际具体类型
Type actualType = pt.getActualTypeArguments()[0];
//强转为字节码对象
this.clazz = (Class) actualType;/////////////////
String className = actualType.getTypeName().toLowerCase();
tableName = className.substring(className.lastIndexOf(".")+1);
}
public T findTById(int id) throws SQLException {
T t = null;
String sql = "select * from " + tableName + " where id = ?;";
QueryRunner runner = new QueryRunner(JdbcUtil.getDatasource());
t = (T) runner.query(sql, new BeanHandler(clazz), id);
return t;
}
}
我对Class baseDaoClass = BaseDao.class;会报错的理解:(先来看完下面代码)
继承泛型Dao类:
如:TopicDao;ReplyDao;TypeDao只需要继承BaseDao,并确定泛型参数
public class TopicDao extends BaseDao<Topic> {
}
public class ReplyDao extends BaseDao<Reply>{
}
public class TypeDao extends BaseDao<Type> {
}
具体使用:
public class DoTest {
@Test
public void doTest () throws SQLException{
TypeDao typeDao = new TypeDao();
Type type = typeDao.findTById(1);
System.out.println("id+title:"+type.getId()+":"+type.getTitle());
System.out.println("==============================================");
TopicDao topicDao = new TopicDao();
Topic topic = topicDao.findTById(1);
System.out.println("id+title:"+topic.getId()+":"+topic.getTitle());
System.out.println("==============================================");
ReplyDao replyDao = new ReplyDao();
Reply reply = replyDao.findTById(1);
System.out.println("id+title:"+reply.getId()+":"+reply.getTitle());
System.out.println("==============================================");
}
}
我对Class baseDaoClass = BaseDao.class;会报错的理解:
//得到字节码对象
//Class baseDaoClass = BaseDao.class;这样会报错的,
Class baseDaoClass = this.getClass();
//得到BaseDao的泛型类型
Type type = baseDaoClass.getGenericSuperclass();
为了方便这里将如上两行代码写成合并形式进行比较:
Type type = this.getClass().getGenericSuperclass();
Type type = BaseDao.class.getGenericSuperclass();
getGenericSuperclass()的到的是父类的泛型类型.
BaseDao的直接父类我们认为是Object,他是没有带泛型信息的,所以会报错。
而this.getClass()就比较有意思了,在使用时候,当TopicDao;ReplyDao;TypeDao任意一个创建实例对象的时候,构造函数会通过Super()调用的父类的构造函数,这里要明白一点,是谁在调用父类的构造方法?答案肯定是子类对象啦。子类对象调用Super()方法,当然,父类构造函数中的this还是指向调用者啦(this代表调用者),也就是子类对象啦。这时候this就有了具体的指向,就是子类实例对象。当然这是站在子类的视角上。如果直接BaseDao bd = new BaseDao(),这是后this.getClass()和BaseDao.class无差别,也会报错。
子类创建实例时候子类中的this和super中的this都是同一个,都只想当前调用者,这里只能用this或者super。目的是通过子类得到父类泛型类型。
所以this很有意思,BaseDao的子类创建实例时,这个this指向的是调用者。
这里我参考了一点资料
大家可以参考一片文章《为什么Java中子类对象和父类对象的hashcode相同? 》
原文链接:http://bbs.csdn.net/topics/392021100?page=1
为了方便,我粘过来了。
class A{
public A(){
System.out.println("father's hashcode : "+this.hashCode());
}
}
class B extends A{
public B(){
System.out.println("child's hashcode : "+this.hashCode());
}
}
public class test{
public static void main(String[] args){
new B();
}
}
==============================
father's hashcode : 1043390835
child's hashcode : 1043390835
请看某位大神解答:
this:
这个关键字始终代表的是调用者,如下伪代码:
A类有方法hashCode(){ System.out.println( this.hashCode());}
创建对象a后
调用:a.hashCode(),其中this就是代表a
在上面代码中,new一个子类的对象时会调用子类中对应的构造方法,在编译后生成.class文件中子类的构造方法会有点变动对应的java代码如下:
public B(){
super();
System.out.println("child's hashCode:" + this.hashCode());
}
这里所加的super();是调用了父类中的构造方法,但是这个父类的构造方法并不是由父类的对象调用的,而是由子类的对象b(注意一个对象在内存中代表一段空间,在创建对象的第一步就是分配空间,生成hash码值,再从创建对象到调用构造函数的过程中虚拟机肯定还做了很多工作)调用构造方法,在执行构造方法的过程中由调用了父类的构造方法,整个过程中并没有创建父类的任何对象,所以调用者还依旧是b对象整个执行的过程中的两个this指针都是对象b,所以最终的hashcode是一样的(为什么在子类对象能调用父类的构造方法而其非子类之间没办法调用? 因为java继承的这个功能就是这样设计的,到此就可以点到为止,等楼主的功力更上几层楼时在去深入研究JVM)
再方法执行的过程中可能会调用其他方法,可能会通过其他对象调用其他方法,也可能通过其他手段如super关键字来调用父类的方法,但this代表的始终是方法的调用者,只有通过对象调用带有this关键字的方法,this才会代表这个对象,否则代表的还是以前的那个对象