Java反射的学习

最近简单了解了java的反射。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。个人理解是,反射是在程序运行时,对未知的类进行操作的一种方法。例如,eclipse的这么多第三方插件,在eclipse在开发时肯定是不会知道有哪些,是未知的。而只要预留了接口,通过反射,就可动态的加载插件,增加系统的可扩展性。
先说一下Object类,Object类是类层次结构的根,Java中所有的类都继承自这个类,也是唯一没有父类的类。在其中声明了一些方法,也就是每个对象都会有的方法,如常见的equals()、toString()、getClass()。

getClass方法就可以获得这个对象的Class对象,如下

方法1:Class c = SomeClass.getClass();
方法2:Class c = Class.forName("类名");
此时可以获得类的各种信息:

     a)Class.getDeclaredField(String name);

     返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

     b)Class.getDeclaredFields();

      返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

     c)Class.getField(String name);

       返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

     d)Class.getFields();

       返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
     。。。。。。

进而就可以创建出这个未知的类的实例。

Object o = c.newInstance();
看到这想起来,刚学数据库的时候会有这样懵逼的一句话,“Class.forName("com.mysql.jdbc.Driver.class").newInstance()”,其实这就是创建了一个驱动对象的实例。

下面来一个小例子试一下:

import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
 * 
 * @author Zongzan
 *注意,getMethods(),getFields()只返回public类型的成员变量或方法
 *Test2类中的b就没有被计算在内.
 *若要返回所有声明的函数,可以用getDeclaredMethods().
 */
class Test2{
	public int a;
	int b;
	public void print(){
	}
}
public class test {
	
	public static void main(String[] args) {
		Test2 it = new Test2();
		Class c = null;
		c = it.getClass();
		Method[] m = c.getMethods();
		Field[] f = c.getFields();
		System.out.println("name :" + c.getName());
		System.out.println("method :" + m[0]);
		System.out.println("field :" + f[0]);
		System.out.println("num of field :" + f.length);
	}
	
}
运行结果:

name :dao.Test2
method :public void dao.Test2.print()
field :public int dao.Test2.a
num of field :1

/***************************************************************割*******************************************************************/

以前写过一个java web的程序,我把每个表都对应了一个Dao,一下就搞了20多个Dao,但是数据库的增删改查变化都不大,每个dao类里面就copy其他类的代码,一不小心就复制错了,很恶心。。。后来才发现,只需要一个Dao,通过反射就可以实现所有表的增删改查。下面是个小例子,不很完整,只用来说明反射在这里的应用。

一、数据库如下:

1.user表


2.message表



二、pojo类

package pojo;

public class User {
	int idUser;
	String userName;
	String sex;
	
	public int getIdUser() {
		return idUser;
	}
	public void setIdUser(int idUser) {
		this.idUser = idUser;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}

}
package pojo;

public class Message {
	int idMessage;
	String recvname;
	String content;
	public int getIdMessage() {
		return idMessage;
	}
	public void setIdMessage(int idMessage) {
		this.idMessage = idMessage;
	}
	public String getRecvname() {
		return recvname;
	}
	public void setRecvname(String recvname) {
		this.recvname = recvname;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
}

三、重点来了,dao类:

package dao;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import util.util;

public class Dao {
	public static String getAddObjectSQL(Object obj){
		
		Class<?> c = obj.getClass();
		Method[] meths = c.getMethods(); //获得所有方法
		Field[] fields = c.getFields();	 //获得所有属性
		String cName = c.getName();		 //获得类名
		//解析获得表名,因此要求pojo中的类的名字和表名一一对应
		//至此得到了组装sql语句中所需的所有信息
		String tableName = cName.substring(cName.lastIndexOf(".") + 1, cName.length());
		//调用getSQL()方法,组装sql语句
		return new util().getSQL(obj, meths, fields, cName, tableName);
		
	}
	
}
通过回调,我们得到了sql语句所需要的各种信息(注意表名是通过解析类的方法名得到的,所以要有规范的命名)。再用一个工具类的getSQL()方法做sql语句的组装:

package util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class util {
	public String getSQL(Object obj, Method[] meths, Field[] fields, String cName, String tableName){
		
		String sql = "insert into ";
		sql += tableName + " (";
      //  System.out.println("表名--" + tableName);
		List<String> mList = new ArrayList<String>();           //每个字段的名字
        List<Object> vList = new ArrayList<Object>();			//字段值
        for (Method method : meths) {
            String mName = method.getName();
            if (mName.startsWith("get") && !mName.startsWith("getClass")) {
                String fieldName = mName.substring(3, mName.length());
                mList.add(fieldName);							//得到每个字段的名字,即“get”后面的部分
               // System.out.println("字段名--" + fieldName);
                try {
                	//value是执行方法返回值,method方法参数为null
                	Object value = method.invoke(obj, null); 	//obj为包含method方法的对象。若有需要,可用Object obj = c.newInstance()创建
                    if (value instanceof String) {
                        vList.add("\"" + value + "\"");
                    //    System.out.println("字段值--" + value);
                    } else {
                        vList.add(value);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        int count = 0;
        for (String s : mList) {
            if (count < mList.size() - 1) {
                sql += s + ",";
            } else {
                sql += s + ") values (";
            }
            count++;
        }
        count = 0;
        for (Object s : vList) {
            if (count < vList.size() - 1) {
                sql += s + ",";
            } else {
                sql += s + ")";
            }
            count++;
        }
        return sql;
	}
}

最后,通过一个测试类来测试一下:

import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.mysql.jdbc.Connection;

import dao.Dao;
import database.DataBase;
import pojo.Message;
import pojo.Relation;
import pojo.User;

public class OprateTest {
	public static void main(String[] args){
		User u = new User();
		u.setIdUser(1);
		u.setSex("man");
		u.setUserName("zongzan");
		Message m = new Message();
		m.setContent("hahahaha~");
		m.setRecvname("zongzan");
		Dao dao = new Dao();
		String sql1 = dao.getAddObjectSQL(u);
		System.out.println("sql1 =" + sql1);
		String sql2 = dao.getAddObjectSQL(m);
		System.out.println("sql2 =" + sql2);
		
		Connection conn = (Connection) DataBase.getConnection();
		PreparedStatement pstmt = null;
		try {
			pstmt =  conn.prepareStatement(sql1);
			pstmt.executeUpdate();
			pstmt =  conn.prepareStatement(sql2);
			pstmt.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("\nInsert Error\n");
		}finally{
			DataBase.freeStatement(conn, pstmt);
		}
		
	}
}
sql语句打印输出为:

sql1 = insert into User (IdUser,Sex,UserName) values (1,"man","zongzan")
sql2 = insert into Message (Content,Recvname,IdMessage) values ("hahahaha~","zongzan",0)

数据库:


这只是个例子,还有很多没做,反射机制会损耗效率,因此应该对反射得到的类做缓存等等。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值