泛型类
public class Generic<T> {
public void methodOne(T) {
}
public void methodTwo(List<?>) {
}
}
声明的泛型类代表在新建的时候不知道要传入什么样的数据类型,因此使用T占位符来声明,在使用泛型类的时候要声明新建的对象的数据类型。可以传进去任何数据类型。
在方法中作参数的时候代表对象在调用该方法的时候必须使用与对象相同的数据类型来当做参数传入。当方法参数为集合的时候只能使用?问号的形式来传入。
public T methodThree() {
}
public List<T> methodFour() {
}
返回类型为T类型和List集合元素类型为T类型的方法
在泛型类或方法中可以对T进行修饰和限制。
public class GenericClass(T extends Serializable) {
}
public class GenericClass(T extends Person) {
}
在泛型中使用extends表示继承(extends)和实现(implements)
public void methodFive(T extends Serializable) {
}
public void MethodSix(T extends Person) {
}
当类已经对T进行修饰和限制的时候方法中的T是已经被限制过的。
public class GenericClass<T extends Serializable> {
public void method(List<T> list) {
}
}
public class GenericClass {
public void method(List<? extends Serializable> list) {
}
}
public class GenericClass {
public <T extends Serializable> void method(List<T> list) {
}
}
占位符T声明的几种方式
1、在类的后面进行声明
2、在方法参数里面声明(? extends Serializable)
3、在方法返回值的前面修饰
public <T extends Serializable> void findAll(List<T>) {
}
当类不是泛型的时候,但是方法还要使用泛型的时候,可以使用后两种方式,对于集合可以使用2、3这两种方式,但是对于单个的参数则必须使用第三种方式,不能再单个参数的情况下使用?问号来表示要传入的参数类型,那个是专门为集合提供的特殊占位符。
当方法参数有两个泛型类型的时候,可以将限制提到方法返回值前面
当方法参数只是用泛型,只能使用<? extends Serializable>这一种方式
Java的反射机制是以后学习所有框架的基础。
反射机制的主要工作:
1、在不能new一个类的对象的时候,通过反射机制来创建一个类的对象
2、在不创建类的对象的时候,获得类的结构(类名、继承结构、实现了哪些接口,有哪些方法)
在使用的时候,要知道类的完全限定名(包名+类名)
通过Class.forName(类的完全限定名)来获得一个类的Class对象,这个Class对象是具有指定名的类的 Class 对象。在这里使用泛型类接收,代表不知道具体是什么类型
Class<T> clazz = Class.forName();
根据类的Class对象来创建出一个指定的类的对象
Object obj = clazz.newInstance();
默认调用类的完全限定名类的无参数的构造方法,当类没有无参数的构造方法的时候会出错。
getMethod(String name)
根据方法名来获得这个方法
getMethods()获得这个Class对象的所有方法
使用这个方法的时候需要引入java.lang.reflect.Method这个包,这个包是java.lang包的子包需要引入。
拿到了方法,可以获得这个方法的名字
String methodName = method.getName();
在获得一个Class对象的时候除了可以使用类的完全限定名还可以使用类名.class来获得一个类的Class对象
方法执行
method.invoke(obj,params);
传入执行这个方法所需的对象以及执行这个方法所需要的参数。
使用invoke执行方法,返回值是Object类型,可以强制类型转换
获得一个类的Class对象的三种方式
1、Class clazz = Class.forName("类的完全限定名");
2、类名.class();
3、对象.getClass();
反射用于PersonRowMapper和StudentRowMapper,根据这些属性让程序自动执行obj.setxxx这样的方法。
BeanPropertyRowMapper(实体属性映射)
用于解决在PersonRowMapper和StudentRowMapper中重复的setxxxx方法,让系统自动生成这样的方法。
在使程序自动产生setxxx这样的方法的时候,首先要获得ResultSet结果集中的所有列名
(遇见这种问题,直接Google)
获取所有列名
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
根据结果集中的列数获得列的名字
for(int i = 1;i <= columnCount;i++) {
String columnName = rsmd.getColumnLabel();
}
获取列的名字有两种方式
1、getColumnName()
2、getColumnLabel()
第一种获得的是列的原始名字,第二种是获得的列的别名(当有别名的时候获得的是列的别名,当没有的时候获得的是列的原始名字)
根据列名获取这个列的值
for (int i = 1; i <= columnCount; i++) {
/
获取列名
getColumnLabel(i)的索引是从1开始
/
String columnName = rsmd.getColumnLabel(i);
Object columnValue = rs.getObject(columnName);
setPropertyValue(obj,columnName,columnValue);
}
根据或的值来调用方法
private void setPropertyValue(T obj,String columnName,Object columnValue) {
String methodName = "set" + columnName.substring(0, 1).toUpperCase()
+ columnName.substring(1);
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if(methodName.equals(method.getName())){
try {
method.invoke(obj, columnValue);
break;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
MapRowMapper:
public class MapRowMapper implements RowMapper<Map<String, Object>>{
@Override
public Map<String, Object> maprow(ResultSet rs){
HashMap<String, Object> map = new HashMap<String,Object>();
ResultSetMetaData rsmd;
try {
rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for(int i = 1;i <= columnCount;i++) {
String columnName = rsmd.getColumnLabel(i);
Object columnValue = rs.getObject(columnName);
map.put(columnName, columnValue);
}
} catch (SQLException e) {
e.printStackTrace();
}
return map;
}
Apache---Commons--DBUtils:可以参考实现
------------------------------------------------------------------------------
ArrayRowMapper:
将查询到的一条记录装到一个对象数组中,数组中的每个对象用来存放对应的值就可以了。
操作步骤与MapRowMapper的操作步骤是一样的。
1、获取一条记录中列的数量
2、获取每列对应的值
3、将对应的值装到对象数组中
jdbc like查询:
Connection conn = DriverManager.getConnection();
String sql = "select from book where bookname like ? or bookauthor like ? or bookpublisher like ?";
String keyword = "%" + keyword +"%";
stat.executeQuery(sql,keyword);
"Y".equalsIgnoreCase(index);关于获取列名称
查两列的效率和查询一列的效率相比,查询一列的效率会更高
在修改实体类的信息的时候,有些字段是不能修改的,例如一个Person的实体类,id是不能修改的,Username也是不能修改的。
java.sql.TimeStamp是java.util.Date的子类,在获得TimeStamp的值的时候,使用TimeStamp这个类来就收该类型的值。
实体类属性:
在给实体类的属性选择类型的时候,统一使用包装类来。
因为在实体类属性(全局变量)不赋值的时候是有默认值的,整数的默认值是0,小数的默认值是0.0.boolean类型的默认值是false。可能到时候使用了一个属性名为score的int类型,当这个值真为0的时候,就不能分辨出这个值是默认值还是已经赋过的值。
因此使用包装类可以解决这种二义性的问题。当没有给这个属性赋值的时候,这个属性的默认值就是null,很容易和赋过值的向区别。
AdminDao只能对Admin类进行CRUD操作,不能对其他类进行数据库的操作