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());
}
}
}