泛型:就是指在类定义时不会设置类中的属性或方法参数的具体类型,而是在类使用时(创建对象)再进行类型的定义。会在编译期检查类型是否错误。
这是泛型的定义,但是对于初学者来说,比较空泛,没有具体的意思,泛型到地址做什么的?此文在代码中讲述泛型的具体使用。
首先,明确一个中心思想,泛型之所以出现肯定是又利于简化代码的,那么如何简化。
举例说明,
例子1:
大家是否使用过mabatis?使用mybatis是否有一些痛点?例如:
对于mybatis生成的逆向工程,每个查询都有一个对应的Example类。他们的构成又是如此相似,此时,此时就可以使用泛型,抽象出一个方法,达到简化代码的目的,不需要每次重复创建Example类。创建BaseEntity,
实体类DiSmartrouteFfm继承。
DiSmartrouteFfm extends BaseEntity<DiSmartrouteFfmExample>
此时,如果在使用mybatis的查询时可以简化如下。
如有前端传参时自动封装了对象,那么只需要两行代码
也许你会疑问,这个不用泛型可不可以,答:可以,但是在BaseEntity的createSelectExample
方法中,返回值必须指定。当然你可以返回Object,然后强转,但是个人感觉,这样做不够优雅,而且容易报错。
所有使用mybatis逆向工程生成出来的实体类都继承BaseEntity,指定返回的Example对象,这样就可以使用泛型简化代码。只有你继承BaseEntity的时候才可以确认指定返回的泛型对象。
(ps:此处的泛型T抽象出来,他符合的是Mybatis生成的mapper映射文件的规则,也就是方法名称是 "andXXXXEqualTo"这种格式。并没有用到extend的强制格式。)
例子2:
我们从后向前推,可以比较容易理解泛型的作用;
public class DiSmartrouteFfmServiceImpl extends BaseServiceImpl<DiSmartrouteFfm,DiSmartrouteFfmMapper> implements DiSmartrouteFfmService { }
public interface DiSmartrouteFfmService extends BaseService<DiSmartrouteFfm>{ }
DiSmartrouteFfmServiceImpl继承BaseServiceImpl<T,D>,实现DiSmartrouteFfmService
public class BaseServiceImpl<T extends BaseEntity,D extends BaseMapper> implements BaseService<T> { @Autowired private D d; @Override public T selectByPrimaryKey(Integer id) { return (T)d.selectByPrimaryKey(id); } @Override public int deleteByPrimaryKey(Integer id) { return d.deleteByPrimaryKey(id); } @Override public List<T> selectByExample(T t) { Object selectExample = t.createSelectExample(); return d.selectByExample(selectExample); } @Override public int updateByPrimaryKey(T t) { DimUser dimUser = (DimUser) ServletUtils.getSession().getAttribute("user"); t.setUpdateUser(dimUser.getUsername()); t.setUpdateTime(new Date()); return d.updateByPrimaryKey(t); } @Override public int updateByPrimaryKeySelective(T t) { DimUser dimUser = (DimUser) ServletUtils.getSession().getAttribute("user"); t.setUpdateUser(dimUser.getUsername()); t.setUpdateTime(new Date()); return d.updateByPrimaryKeySelective(t); } @Override public int add(T t) { DimUser dimUser = (DimUser) ServletUtils.getSession().getAttribute("user"); t.setCreateUser(dimUser.getUsername()); t.setCreateTime(new Date()); t.setUpdateUser(dimUser.getUsername()); t.setUpdateTime(new Date()); return d.insertSelective(t); } }
BaseService接口
public interface BaseService<T> { T selectByPrimaryKey(Integer id); int deleteByPrimaryKey(Integer id); public List<T> selectByExample(T t); public int updateByPrimaryKey(T t); public int updateByPrimaryKeySelective(T t); public int add(T t); }
BaseMapper接口
public interface BaseMapper<T,E> { int deleteByPrimaryKey(Integer id); T selectByPrimaryKey(Integer id); List<T> selectByExample(E e); int updateByPrimaryKey(T t); int insertSelective(T t); int insert(T t); int updateByPrimaryKeySelective(T t); }
其中,T可以在使用的时候设置实体类,E可以在使用的时候设置Example查询类。
这样,如有一个新的实体类serviceImpl,可以直接按上述方式实现service<T,D>并指定T,E。就可以继承BaseService中的对应方法,可以高效运用selectByExample,updateByPrimaryKey更新时自动注入时间,user,add新增是自动加入时间,user。达到了简化代码的目的。前提对应的mapper映射xml文件有对应的方法,(如果是mybatis逆向工程生成的都会有。直接用即可)。