反射技术

18 篇文章 0 订阅

1、反射机制的介绍

         class的获取

     反射机制是Java的动态性之一

动态语言:在程序运行时,可以改变程序的结构或变量的类型

<html>
	<head>
		<title>js代码</title>
		<script>
			function test(){
				var s="var a=3;var b=4;alert(a+b);";
				eval(s);
			}
		</script>
	</head>
	<body>
		<input type="button" onclick="test()" value="测试"/>
	</body>
</html>

典型的动态语言:Python、ruby、JavaScript

C、C++、Java不是动态语言,但是具有一定的动态性,可以称为准动态语言,具备类似动态语言的特性。

反射机制

  程序在运行的过程中加载一些只知道相关名字的类

Class clazz = Class.forName("com.xjion.reflect.User");

     一个类在被加载后,JVM会创建一个对应类的Class对象,类的整个结构信息会被放到Class对象中。

这个Class对象就像镜子一样,通过这面镜子,可以得到对应类的全部信息。

反射机制的常见作用

1)动态的加载类、动态的获取类的信息(属性、方法、构造器)

2)动态构造对象

3)动态调用类和对象的任意方法、构造器

4)动态调用个处理属性

5)获取泛型的信息

6)处理注解

获取Class对象的三种方式

1)通过字节码文件获取

2)对象的getClass()方法

3)Class类的静态方法forName(类的地址)

import com.xjion.entity.User;

public class Test {
	public static void main(String[] args) throws ClassNotFoundException {
		System.out.println(int.class);
		System.out.println(void.class);
		int[] arrA = new int[10];
		int[] arrB = new int[10];
		/**维数相同和类型相同的数组共享同一个Class对象*/
		System.out.println(arrA.getClass()==arrB.getClass());
		
		/**同一个类的N多对象,共享同一个Class对象*/
		User u1 = new User();
		User u2 = new User();
		System.out.println(u1.getClass()==u2.getClass());
		
		/**获取Class对象的三种方式*/
		//(1)通过对象的getClass()方法获取
		Class c1 = u1.getClass();
		//(2)通过字节码文件获取
		Class c2 = User.class;
		//(3)通过Class类的静态方法获取
		Class c3 = Class.forName("com.java.entity.User");
		System.out.println((c1==c2)+"\t"+(c1==c3));
	}
}

反射机制动态操作、方法、属性、构造器

获取类的名字

方法描述
String getName()获取包名+类名
String getSimpleName()获取类的名字

获取类的属性

方法描述
Field getField(String fieldName)得到公共的属性对象
Field getDeclareField(String fieldName)得到指定名称的属性对象
Field[] c.getDeclaredFields得到所有的属性对象

获取类的方法

方法描述
Method[] getDeclaredMethods得到所有的方法对象
Method[] c.getMethods()得到父类及本类中的公共的方法对象
Method getDeclaredMethod(String methodName,Class...type)得到本类或父类中的公共的方法对象

获取构造方法

方法描述
Constructor[] getDeclaredConstructors()得到公共的构造 方法的对象
Constructor [] getConstructors()得到公共的构造 方法对象

Constructor getDeclaredConstructor(Class…type)

得到指定参数的公共的构造方法对象
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException {
		String path = "com.java.entity.User";
		//(1)获取类的名称
		Class c = Class.forName(path);
		System.out.println("类的全名称:"+c.getName());
		System.out.println("类的名称:"+c.getSimpleName());
		
		//获取父类的Class对象
		Class cSuper = c.getSuperclass();
		System.out.println(cSuper.getName());
		System.out.println(cSuper.getSimpleName());
		
		//(2)获取类的属性信息
		//Field f = c.getField("userId");//只能获取公共的属性
		//System.out.println(f);
		Field[] fields = c.getFields(); //只能获取公共的属性
		System.out.println(fields.length);
		
		Field[] fields2 = c.getDeclaredFields();
		System.out.println(fields2.length);
		for (Field field : fields2) {
			System.out.println(field);
			System.out.println(field.getModifiers()+"\t"+field.getType()+"\t"+field.getName());		
		}
		
		//(3)获取类的方法信息
		Method[] methods = c.getDeclaredMethods();
		System.out.println(methods.length);
		for (Method method : methods) {
			System.out.println(method);
			System.out.println("访问权限"+method.getModifiers());
			System.out.println("返回值类型:"+method.getReturnType());
			System.out.println("方法的名称:"+method.getName());
			//获取方法的参数
			Class[] cPara = method.getParameterTypes();
			for (Class c1 : cPara) {
				System.out.println(c1.getTypeName()+"\t");
			}
			System.out.println("\n-----------------------");
		}
		System.out.println("-------------------------");
		//(4)获取类的构造器
		Constructor[] cons = c.getConstructors();
		for (Constructor constructor : cons) {
			System.out.println(constructor);
		}
		System.out.println("\n==================");
		//获取指定的构造方法
		Constructor con = c.getConstructor(null);
		System.out.println(con);
		System.out.println("\n-------------------------");
		Constructor con2 = c.getConstructor(int.class,String.class,String.class);
		System.out.println(con2);
	}
}

动态操作属性、方法、构造方法

public class Test2 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
		//获得Class类的对象
		Class c = Class.forName("com.java.entity.User");
		//(1)得到无参构造方法的对象
		Constructor con = c.getConstructor(null);
		//通过无参构造方法的对象,创建User类的对象
		User user = (User)con.newInstance();
		
		//(2)动态操作属性
		Field field = c.getDeclaredField("userId");
		field.setAccessible(true);//这个属性不需要做安全检查了,可以直接访问
		field.set(user, 1001);
		System.out.println("取出userId这个属性的值:"+field.get(user));//通过反射直接取值
		
		//(3)动态操作方法
		Method m = c.getDeclaredMethod("setUserName", String.class);
		//执行setUserName这个方法
		m.invoke(user, "张三");
		Method m2 = c.getDeclaredMethod("getUserName", null);
		System.out.println(m2.invoke(user));
	}
}

提高反射的效率

反射机制对程序运行在性能上有一定的影响,速度慢

提高反射性能的方法

1)通过setAccessible提高性能

setAccessible启用和禁用访问安全监测的开关,true打开,false关闭

禁用安全监测,可以提高反射的运行速度,但不安全

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
	public static void test01(){
		Object obj = new Object();
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < 1000000000L;i++) {
			obj.hashCode();
		}
		long endTime = System.currentTimeMillis();	
		System.out.println("调用普通方法,执行10亿次:"+(endTime-startTime)+"ms");
	}
	public static void test02() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		Object obj = new Object();
		Class c =obj.getClass();
		//获取指定方法
		Method m = c.getDeclaredMethod("hashCode", null);
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < 1000000000L;i++) {
			m.invoke(obj, null);
		}
		long endTime = System.currentTimeMillis();	
		System.out.println("调用反射,执行10亿次:"+(endTime-startTime)+"ms");
	}
	public static void test03() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Object obj = new Object();
		Class c =obj.getClass();
		//获取指定方法
		Method m = c.getDeclaredMethod("hashCode", null);
		m.setAccessible(true); //不执行安全检查
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < 1000000000L;i++) {
			m.invoke(obj, null);
		}
		long endTime = System.currentTimeMillis();	
		System.out.println("调用反射,执行10亿次:"+(endTime-startTime)+"ms");
	}
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		test01();
		test02();
		test03();
	}
}

调用普通方法,执行10亿次:900ms

调用反射,执行10亿次:2100ms

调用反射,执行10亿次:1500ms

注解

注解的作用

(1)不是程序本身,可以对程序作出解释。(这一点跟注释没有什么区别)。
(2)可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别,如果没有注解信息处理流程,则注解毫无意义)

注解的格式

(1)注解是一“@注释名”在代码中存在,还可以添加一些参数值,例如@SuppressWarnings(value=“unchecked”)。

注解在哪里使用

(1)可以附加在package,class,method,field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元素的访问。

内置的注解

(1)@Override 标识方法是重写的方法
(2)@Deprecated 标识的方法不建议使用
(3)@SuppressWarnings 用来抑制编译时的警告信息
(4)@SuppressWarinings 需要提供参数才能正常使用,这些参数都是已经定义好的,我们只需要选择就可以了。
 

参数说明
deprecation使用了过时的类或方法的警告
unchecked执行了未检查的装换是时的警告,如使用集合时未指定泛型
fallthrough当在使用switch语句使用时发生穿透
path在类路径、源文件路径等中有不存在路径的警告
serial当在可序列化的类上缺少serialVersionUID定义时的警告
finally任何finally字句不能完成时的警告
all关于以上所有情况的警告

举例:
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked”,“deprecation”})

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TestAnnotation {
	@Override
	public String toString() {
		return super.toString();
	}
	@Deprecated
	public void show() {
		Date d = new Date();
		System.out.println(d.getYear());
	}
	@SuppressWarnings("all")
	public void method() {
		List list = new ArrayList();
	}
	@SuppressWarnings(value={"unchecked","path"})
	public static void main(String[] args) {
		new TestAnnotation().show();
	}
}

ORM映射

ORM:对象关系映射,JavaBean和数据库的表一一对应的映射关系

写程序用Java来写,存数据用数据库存储

å¨è¿éæå¥å¾çæè¿°

(1)类与表结构对应
(2)属性和字段对应
(3)对象和记录对应
使用注解完成类和表结构的映射关系

使用反射技术封装JDBC工具

1、封装一个加载驱动,获取连接,关闭资源的类

package com.xjion.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class DBUtil {
	private static String driver = "";
	private static String url = "";
	private static String user = "";
	private static String pwd = "";
	/**
	 * 类加载时获取用户信息和加载数据库的驱动
	 */
	static {
		try {
			Properties properties = new Properties();
			properties.load(DBUtil.class.getResourceAsStream("/db.properties"));
			driver = properties.getProperty("driver");
			url = properties.getProperty("url");
			user = properties.getProperty("username");
			pwd = properties.getProperty("password");
			Class.forName(driver);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取数据库的连接
	 * @return
	 */
	public static Connection getConnection() {
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(url,user,pwd);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}
	
	/**
	 * 关闭数据库流资源
	 * @param objs 需要关闭的流数组
	 */
	public static void close(Object...objs) {
		if(objs != null) {
			try {
				for (Object obj : objs) {
					if (obj instanceof Connection) {
						((Connection)obj).close();
					}else if (obj instanceof PreparedStatement) {
						((PreparedStatement)obj).close();
					}else if(obj instanceof ResultSet) {
						((ResultSet)obj).close();
					}
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

2、封装一个简单的支持全表查询的类

package com.xjion.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import com.xjion.po.User;
/**
 * 版本一:不使用泛型的简单封装
 * 封装思想:
 * 		对po中所有的属性注入,所以只能支持全表查询
 * @author xjion
 */
public class BaseDao {
	
	/**
	 * 支持全表查询
	 * 		select * from user;
	 */
	public static List<Object> queryAll(String sql,Class class1){
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		List<Object> list=new ArrayList<Object>();
		try {
			conn=DBUtil.getConnection();
			//获取st对象   
			ps=conn.prepareStatement(sql);
			//执行sql语句
			rs=ps.executeQuery();
			//遍历结果集
			while(rs.next()){
				Object obj = class1.newInstance();
				Field[] fields = class1.getDeclaredFields();
				for (Field field : fields) {
					String fieldName = field.getName();
					Object value = rs.getObject(fieldName);
					//根据设定器set方法设置值
					Method setter = class1.getMethod(getSetter(fieldName), field.getType());
					setter.invoke(obj, value);
				}
				list.add(obj);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			DBUtil.close(rs,ps,conn);
		}
		return list;
	}
	
	//拼接设定器的名字
	private static String getSetter(String fieldName) {
		return "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
	}
	
	//测试
	public static void main(String[] args) {
		BaseDao.queryAll("select * from user",User.class);
        System.out.println(obj);
	}
}

3、封装一个使用泛型的支持所有查询的类

package com.xjion.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

import com.xjion.po.User;

/**
 * 使用反射和泛型封装的支持全部查询的JDBC方法
 * 封装思想:
 * 		根据查询出来已有的字段去匹配po中的字段注入
 * @author xjion
 */
public class BaseDao2 {
	
	public static <T> List<T> queryAll(String sql,Class<T> clazz,Object...params){
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		List<T> list=new ArrayList<T>();
		try {
			conn=DBUtil.getConnection();
			//获取st对象   
			ps=conn.prepareStatement(sql);
			//查看是否需要填坑
			if (params != null) {
				for (int i = 0; i < params.length; i++) {
					ps.setObject(i+1, params[i]);
				}
			}
			//执行sql语句
			rs=ps.executeQuery();
			//获取查询出来的所有字段信息
			ResultSetMetaData resultSetMetaData = rs.getMetaData();
			//获取字段数
			int count = resultSetMetaData.getColumnCount();
			//遍历结果集
			while(rs.next()){
				T t = clazz.newInstance();
				for (int i = 1; i <= count; i++) {
					//获取每个字段的属性名
					String fieldName = resultSetMetaData.getColumnName(i);
					//获取属性
					Field field = clazz.getDeclaredField(fieldName);
					//获取属性的值
					Object value = rs.getObject(fieldName);
					//设定器
					Method setter = clazz.getMethod(BaseDao2.getSetter(fieldName), field.getType());
					//注入
					setter.invoke(t, value);
				}
				list.add(t);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			DBUtil.close(rs,ps,conn);
		}
		return list;
	}
	
	//拼接设定器的名字
	private static String getSetter(String fieldName) {
		return "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
	}
	
	//测试
	public static void main(String[] args) {
		List<User> users = BaseDao2.queryAll("select uname from user where id=?",User.class,1);
		for (User user : users) {
			System.out.println(user.getUname());
		}
	}
	
}

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值