• Java反射入门


      Java这么多高灵活性,非常多都是利用反射来实现的,所谓的反射是指,编译期间全然未知的classes,执行时,对任一个类(依据类名-字符串),可以知道这个类的全部属性和方法;对于任一个对象,都可以调用它的随意一个方法和属性。

         简而言之,Java反射机制主要提供了下面功能:

      Ø  在执行时推断随意一个对象所属的类obj.getClass()

      Ø  在执行时构造随意一个类的对象

      Ø  在执行时推断随意一个类所具有的成员变量和方法

      Ø  在执行时调用随意一个对象的方法

      以下我们先用一个简单小例体现一下Java Reflect上述的功能,然后模拟一下Java Reflect应用之中的一个Hibernate ORMapping的实现。

     

    Java反射功能測试

      首先定义一个User.java类,代码例如以下:

    package reflect;
    
    /**
     *  @author--zhipeng 
     */
    public class User {
    
    	private String name;
    	
    	//构造方法1(默认构造方法)***********************
    	public User(){
    		
    	}
    	//构造方法2
    	public User(String name){
    		this.name=name;
    	}
    	//******自己定义方法*************
    	public void getMessage(){
    		System.out.print("kobe bryant never stop trying");
    	}
    	//******重写toString方法,在測试的时候会用到*****
    	@Override
    	public String toString() {
    		return "name:"+this.name;
    	}
    	//**************************
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    
    }
    

      以下我将在ReflectTest.java类中,首先获得User的类名,然后依据类名来获得类的方法、属性、注解等,并调用方法,代码例如以下:

    package reflect;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    import reflect.User;
    
    /**
     *  @author--zhipeng 
     */
    public class ReflectTest {
    
    	public static void main(String[] args) throws Exception {
    		Class clazz = User.class;//获得User的类名,返回reflect.User
    		Object obj = create(clazz);//创建User的一个对象
    		System.out.println(obj);//输出对象,会调用对象的toString方法
    		System.out.println("---------");
    		invoke1(obj, "getMessage");//调用User对象的getMessage方法
    	}
    	/*
    	**依据类名,new一个对象,并返回*/
    	static Object create(Class clazz) throws Exception {
    		//假设clazz含有无參数的构造方法,能够例如以下方式实例化
    		//clazz.newInstance();
    		//依据类名和參数(类型、个数),找到对应的构造方法-以下创建构造方法參数为String的构造方法
    		Constructor con=clazz.getConstructor(String.class);
    		//实例化对象
    		Object obj=con.newInstance("myName is zhipeng");
    		//返回对象
    		return obj;
    	}
    	/*
    	**依据对象,方法名(字符串),来调用方法*/
    	static void invoke1(Object obj, String methodName)throws Exception{
    		//getDeclaredMethods能够获取类本身(不包含父类)全部方法的名字(包含私有方法)**一般不用这样的方法,私有的属性一般不能改动
    		Method[] ms = obj.getClass().getDeclaredMethods();
    		//getMethods能够获取类本身,以及父类的方法的名字,但不包含私有的方法
    		ms = obj.getClass().getMethods();
    		for (Method m : ms) {
    			//假设方法名字匹配,则反射调用方法
    			if (methodName.equals(m.getName()))
    				m.invoke(obj, null);
    		}
    		/*
    		**防止方法重载,可用以下的方式(能够指明參数)--与上面的for循环(无法防止方法重载)一个效果
    		**Method m = obj.getClass().getMethod(methodName, null);
    		**m.invoke(obj, null);
    		*/
    	}
    	
    	/*
    	**依据类名获取类的属性(一般不直接操作属性)*/
    	static void field(Class clazz) throws Exception {
    		Field[] fs = clazz.getDeclaredFields();
    		//fs = clazz.getFields();
    		for (Field f : fs)
    			System.out.println(f.getName());
    	}
    	/*
    	**依据类名获取类的注解*/
    	static void annon(Class clazz) throws Exception {
    		Annotation[] as = clazz.getAnnotations();
    		for (Annotation a : as)
    			System.out.println(a.getName());
    	}
    
    }

      执行结果:   

    简单模拟ORMapping

      上面我们測试了Java反射所提供的基本功能,以下简单模拟HibernateOR映射,基本思路就是传入sql语句,将结果集包装为object,并将结果集的字段与object的属性映射好,代码例如以下:

    package reflect;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     *  @author--zhipeng 
     */
    public class ORMTest {
    
    	public static void main(String[] args)throws Exception{
    		//将select结果集(这里为一条)包装为User对象,并将结果集的字段,与User对象的属性映射
    		User user = (User) getObject(
    				"select id as Id, name as Name, birthday as Birthday, money as Money  from user where id=1",
    				User.class);
    		System.out.println(user);
    	}
    	//获取一个ResultSet的字段(列)名
    	private static String[] getColNames(ResultSet rs) throws SQLException {
    		ResultSetMetaData rsmd = rs.getMetaData();
    		int count = rsmd.getColumnCount();
    		String[] colNames = new String[count];
    		for (int i = 1; i <= count; i++) {
    			colNames[i - 1] = rsmd.getColumnLabel(i);
    		}
    		return colNames;
    	}
    	//传入一个sql语句与类名,返回一个对应类的对象
    	static Object getObject(String sql, Class clazz) throws SQLException,Exception,
    	 IllegalAccessException, InvocationTargetException
    	{
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet rs = null;
    		try {
    			//JdbcUtils为自己定义类-这里不多介绍
    			conn = JdbcUtils.getConnection();
    			ps = conn.prepareStatement(sql);
    			rs = ps.executeQuery();
    			//获取sql语句运行结果集的列名
    			String[] colNames = getColNames(rs);
    			Object obj=null;
    			//获取clazz的全部方法名
    			Method[] ms = clazz.getMethods();
    			while (rs.next()) {
    				obj = clazz.newInstance();//要求类必须有參数为空的构造方法,相似Hibernate
    				for (int i = 0; i < colNames.length; i++) {
    				//用set+"字段名"来匹配,实体类中字段的set方法
    					String colName = colNames[i];
    					String methodName = "set" + colName;
    					//OR映射
    					for (Method m : ms) {
    						if (methodName.equals(m.getName())) {
    							m.invoke(obj, rs.getObject(colName));
    							break;
    						}
    					}
    				}
    			}
    			return obj;
    		} finally {
    			JdbcUtils.free(rs, ps, conn);
    		}
    	}
    }

      上面的getObject(String sql, Class clazz)方法为映射一条数据,假设映射多条数据可改方法为:

    	static List<Object> getObjects(String sql, Class clazz)
    			throws SQLException, Exception, IllegalAccessException,
    			InvocationTargetException {
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet rs = null;
    		try {
    			conn = JdbcUtils.getConnection();
    			ps = conn.prepareStatement(sql);
    			rs = ps.executeQuery();
    			String[] colNames = getColNames(rs);
    
    			List<Object> objects = new ArrayList<Object>();
    			Method[] ms = clazz.getMethods();
    			while (rs.next()) {
    				Object object = clazz.newInstance();
    				for (int i = 0; i < colNames.length; i++) {
    					String colName = colNames[i];
    					String methodName = "set" + colName;
    					for (Method m : ms) {
    						if (methodName.equals(m.getName())) {
    							m.invoke(object, rs.getObject(colName));
    							break;
    						}
    					}
    					objects.add(object);
    				}
    			}
    			return objects;
    		} finally {
    			JdbcUtils.free(rs, ps, conn);
    		}
    	}

     

    总结

      Java反射这么灵活,无非是将曾经“编译时”必须做的事推迟到了“执行时”,而方式也就是由原先的对象到了灵活可配的“字符串”。

      上面的映射方式是用构造字符串方式,set+”字段名映射类的属性,Hibernate的映射当然要灵活复杂的多,通过配置文件来配置。可是实现原理差点儿相同,Java映射为Java灵活性做了非常好的支持。

  • 相关阅读:
    C# macro function via #define __FILE__ __LINE__ ___FUNCTION__ __DATE__ __TIME__
    3
    2月23号
    3月26
    impala故障
    2月3号日更
    HDFS某个节点的磁盘满了
    3月2
    mq集群
    3月3
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4260665.html
Copyright © 2020-2023  润新知