jDBC代码分层
从上面的文章中,我们的代码分层主要是一个实体类对应一个数据库表,Action类也就只是针对这个数据库表的操作,这样就会导致我们的代码并不灵活,遇到其他数据库表就可能会出现操作不了的情况.这时候写成通用的逻辑,调用方法的时候不管我们传入什么样的数据类型都能匹配到.这里我们就需要使用到反射.
反射可以说是Java中最强大的技术之一,在我们日常工作中也会有非常多的场景会用到.
·JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为JAVA语言的反射机制.
· 要想解刨一个类,必须先要获取到该类的字节码文件对象,而解刨使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象
我们先来看一下类的加载过程
如图所示,我们刚开始写文件的时候,写的是*.java文件,里面主要是一些字符串,经过编译后会生成 *.class文件,这文件只有机器能读懂,类加载器将Class文件加载到jvm空间里面,在new一个对象的时候会创建一个 p1、p2的内存空间.但任何一个对象在生成前都会预先在内存空间中生成一个Class对象,这个对象里面会包含我们的泛型.以及我们类的信息
Class类的实例对象表示正在运行的JAVA应用程序中的类和接口,每个类只会产生一个class对象,在类加载的时候会自动创建
反射就是自己手动获取到Class的实力对象,通过操作类里面的成员变量、成员方法以及构造方法.
以下是获取class对象的方式
public class CreateClassObject {
public static void main(String[] args) {
try {
//1.通过class.forname()来获取class对象
Class aClass = Class.forName("com.jdbcUtil.Entity.Emp");
System.out.println(aClass.getPackage());
System.out.println(aClass.getName());
System.out.println(aClass.getSimpleName());
System.out.println(aClass.getCanonicalName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//2。通过类名.class 来获取
Class empClass = Emp.class;
//3.通过对象的getClass() 来获取
Class aClass = new Emp().getClass();
//以上三种获取class对象方式效果基本一样。不过工作上推荐使用第一种和第二种。第三种方式在第三方包的调用中不方便。
//4.如果是一个基本数据类型,那么可以通过TYPE方式来获取Class对象
Class type = Integer.TYPE;//通过数据类型.TYPE可以获取到数据类型的class对象
}
}
常用反射调用方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//获取成员变量
Class aClass = Class.forName("reflect.Student");
/*Field[] fields = aClass.getFields();//获取当前类及父类的成员变量(只能获取到public权限的)
for (Field field : fields) {
System.out.println(field);
System.out.println(field.getName());//获取字段名字
System.out.println(field.getType());//获取字段类型
System.out.println(field.getModifiers());//获取访问修饰符
}*/
//反射在一定程度上破坏了封装性,需要合理使用
/*Field[] declaredFields = aClass.getDeclaredFields();//获取当前类的所有属性,不仅仅局限于公共访问修饰符,所有的访问修饰符都可以拿到
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
System.out.println(declaredField.getName());
}*/
//反射在一定程度上破坏了封装性,需要合理使用
/*Field age = aClass.getDeclaredField("age");//获取私有属性
age.setAccessible(true);//设置该属性是否被访问,true表示能被访问,破坏了封装性
System.out.println(age.getName());
Object o = aClass.newInstance();
age.set(o,10);//给私有属性赋值
System.out.println();
System.out.println(((Student)o).getAge());
// System.out.println(((Student)o).laught());//获取私有方法
*/
//获取该对象的普通方法包含的方法范围时当前对象及父类对象的所有公共方法
/*Method[] methods = aClass.getMethods();
for (Method method : methods) {
// System.out.println(method);
System.out.println(method.getName());
// System.out.println(method.getModifiers());
// System.out.println(method.getReturnType());
}*/
//获取当前类中所有方法,无论是什么访问修饰符
/* Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
Method laught = aClass.getDeclaredMethod("laught");//获取私有方法
laught.setAccessible(true);//设置该私有方法是否被访问
Method acount = aClass.getDeclaredMethod("acount", int.class, int.class, String.class);
acount.setAccessible(true);
Object o1 = aClass.newInstance();//生成成员对象
System.out.println(laught.invoke(o1));//调用私有方法
System.out.println(acount.invoke(o1,7,8,"haha"));
*/
//获取对象的所有构造方法,只能获取公有的构造方法
/*Constructor[] constructors = aClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName());
}*/
//获取所有构造方法,无论是公有还是私有
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor.getName());
}
//调用私有构造方法
Constructor declaredConstructor = aClass.getDeclaredConstructor(int.class);
declaredConstructor.setAccessible(true);
Student o2 = (Student)declaredConstructor.newInstance(3);
System.out.println(o2);
}
接下来我们就依照上面例子中所用到的方法,编写一个类文件.(要求查询N张表的数据,但是不想写N多的方法,能否写一个方法完成所有表的查询工作)
package reflect;
import com.jdbcUtil.Entity.Emp;
import com.jdbcUtil.Util.DBUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class BaseImpl {
/**
*
* @param sql 需要查询的sql语句
* @param params 需要用到的参数数组
* @param clakk 返回查询到的的数据列表类型
* @return
*/
public List getRow(String sql,Object[] params,Class clakk) {
List list = new ArrayList();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
preparedStatement = connection.prepareStatement(sql);
if (params!=null){
for (int i=0;i<params.length;i++){
preparedStatement.setObject(i+1,params[i]);
}
}
//开始执行查询
resultSet= preparedStatement.executeQuery();
//将返回的结果方知道不同的对象中
ResultSetMetaData metaData = resultSet.getMetaData();//获取结果集合的原数据对象
int columnCount = metaData.getColumnCount();//获取查询到的每一行的记录中包含多少个列
//循环遍历resultSet
while (resultSet.next()){
try {
Object object = clakk.newInstance();//放置创建具体结果属性的对象
for (int i=0;i<columnCount;i++){
Object objValue = resultSet.getObject(i+1);//获取单一列的值
String columName = metaData.getColumnName(i+1).toLowerCase();//获取列的名称
Field declaredField = clakk.getDeclaredField(columName);//获取类中的属性
//获取类中属性对应的方法
Method method = clakk.getMethod(getSetName(columName),declaredField.getType());
if (objValue instanceof Number){
//匹配值的数据类型
Number number = (Number) objValue;
String fname = declaredField.getType().getName();
if ("int".equals(fname)||"java.lang.Integer".equals(fname)){
method.invoke(object,number.intValue());//调用set方法
}else if ("byte".equals(fname)||"java.lang.Byte".equals(fname)){
method.invoke(object,number.byteValue());//映射对象类调用方法设置参数
}else if ("short".equals(fname)||"java.lang.Short".equals(fname)){
method.invoke(object,number.shortValue());
}else if ("long".equals(fname)||"java.lang.Long".equals(fname)){
method.invoke(object,number.longValue());
}else if ("float".equals(fname)||"java.lang.Float".equals(fname)){
method.invoke(object,number.floatValue());
}else if ("double".equals(fname)||"java.lang.Double".equals(fname)){
method.invoke(object,number.doubleValue());
}
}else {
if (objValue instanceof Date){
//日期格式转字符串
objValue = objValue.toString();
}
method.invoke(object,objValue);
}
}
list.add(object);//将每一行的内容生成的对象添加到list中
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.closeConnection(connection,preparedStatement,resultSet);
}
return list;
}
public String getSetName(String Name){
//返回设置对象类中的Set 方法名称
return "set"+Name.substring(0,1).toUpperCase()+Name.substring(1);
}
public static void main(String[] args) {
// System.out.println(new BaseImpl().getSetName("empo"));
BaseImpl base = new BaseImpl();
List row = base.getRow("select * from emp where empname=?", new Object[]{
"lisi"}, Emp.class);
for (Iterator it=row.iterator();it.hasNext();){
Emp emp = (Emp) it.next();
System.out.println(emp);
}
}
}