---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
一、概述
在Java中非常重要的就是反射机制,在正常情况下如果有一个类,则肯定能够通过类创建对象;如果想要使用类的完整名称来创建对象的话,就需要用到Java的反射机制,Java反射机制的基石是Class类Class类表示所有类的本身【也就是一个类在内存中的字节码】,通过Class可以获取到一个类的完整结构,包括此类中的方法、属性、包名、类名等等...
Class类的常用方法:(注意Class类没有公开的构造方法【构造方法是私有的】)
静态方法:Class.forName("类的完整名称");通过此方法能够得到Class类的对象
Class类获取对象的3个基本方式:
1、对象.getClass()
2、类名.class
3、Class.forName("")
一般方法:
getConstructors()得到一个类的所有构造方法
getConstructor(Class...)得到指定的构造方法
getDeclaredFields()得到类中全部属性
getFields()得到类中继承来的或者本类中的public类型的字段
getMethods()得到类中的全部方法
getMethod(String Class)根据方法名称与参数类型获取类中的方法
getInterfaces()得到类所有实现的接口
getName()得到类的名称
getPackage()得到类的包名
getSupperClass()得到类的父类
newInstance()调用类的无参构造方法,实例化该类
getComponentType()返回表示数组类型的Class
isArray()是否数组
下面对各个方法做一个简要的介绍
package com.itheima.hightech;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception{
//1.得到Student类的所有构造方法
Class<Student> clazz = Student.class;
Constructor<?>[] cs = clazz.getConstructors();
for (Constructor<?> constructor : cs) {
System.out.println("这是全部构造方法的其中一个:"+constructor);
}
//2.得到Student类的有参数的构造方法
Constructor<?> c = clazz.getConstructor(int.class,String.class);
System.out.println("这是得到的指定的构造方法:"+c);
//3.得到Student类中的全部字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("类中的字段:"+field);
}
//这个应该是得到类中继承来的或者本类中的public类型的字段
Field[] fields2 = clazz.getFields();
for (Field field : fields2) {
System.out.println("继承来的或者本类中的public类型字段:"+field);
}
//得到Student类中的全部方法,包括父类中的非私有的方法
Method[] ms = clazz.getMethods();
for (Method method : ms) {
System.out.println("全部方法:"+method);
}
//得到Student类中的指定的方法sayAge()
Method m = clazz.getMethod("sayAge");
System.out.println("指定方法:"+m);
//得到Student类实现的全部接口,不包括父类实现的接口
Class<?>[] cls = clazz.getInterfaces();
for (Class<?> cl : cls) {
System.out.println("全部接口:"+cl);
}
//得到类的名称
System.out.println(clazz.getName());
//得到包的名称
System.out.println(clazz.getPackage());
//得到类的父类
System.out.println(clazz.getSuperclass());
//得到类的继承关系列表
Class<?> supperClazz = clazz.getSuperclass();
while(true){
System.out.println("继承关系:"+supperClazz);
supperClazz = supperClazz.getSuperclass();
if(supperClazz == Object.class){
System.out.println("继承关系:class java.lang.Object");
break;
}
}
int[] arr = {1,2};
//判断是否数组
System.out.println(arr.getClass().isArray());
//得到数组类型的名称
System.out.println(arr.getClass());
//如果是数组,得到数组中元素的类型
if(arr.getClass().isArray()){
System.out.println("数组中元素的类型:"+arr.getClass().getComponentType());
}
}
}
class Person implements Serializable{
/**
*
*/
private static final long serialVersionUID = 591343829826564664L;
public int id;
protected String summary;
}
class Student extends Person implements Serializable{
/**
*
*/
private static final long serialVersionUID = 6857111643274069272L;
protected String desc;
public Student(){}
public Student(int age,String name){
this.age = age;
this.name = name;
}
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sayAge(){
System.out.println("我的年龄是:"+age);
}
}
二、反射中的几个重要的类
1、Constructor 表示类中构造方法的类
2、Method 表示类中方法的类
3、Field 表示类中字段的类
分类介绍:
A、Constructor类
Constructor的获取可以有如下4中方式获得:
clazz.getConstructors() 获取所有的public修饰的构造方法
clazz.getConstructor(Class...c)根据参数类型获取指定的public修饰的构造方法
clazz.getDeclaredConstructors()获取类中所有的构造方法,包括private修饰的
clazz.getDeclaredConstructor(Class...)根据参数类型获取指定的构造方法,包括private修饰的
Constructor中常用的方法
package com.itheima.hightech;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* 构造方法使用简单实例
*/
public class ConstructorDemo {
public static void main(String[] args) throws Exception{
List<String> list = new MyArrayList();
Type type = list.getClass().getGenericSuperclass();
//得到构造方法,包含私有的构造方法
Constructor<?> c1 = list.getClass().getDeclaredConstructor(String.class);
//暴力反射,使构造方法变为可对外访问的
c1.setAccessible(true);
//根据构造方法获取该类的实例
MyArrayList instance = (MyArrayList) c1.newInstance("dsfds");
//访问变量的属性值
System.out.println(instance.str);
//访问变量的方法
instance.add("11");
//得到MyArrayList的泛型实际参数类型
if(type instanceof ParameterizedType){
ParameterizedType ptype = (ParameterizedType)type;
Type[] as = ptype.getActualTypeArguments();
for (Type a : as) {
System.out.println(a instanceof Class<?>);
System.out.println(a);
}
}
//获取类上的所有Annotation
Annotation[] anns = list.getClass().getAnnotations();
for (Annotation ann : anns) {
System.out.println(ann);
}
//得到某一个annotation
MyAnnotation ann = list.getClass().getAnnotation(MyAnnotation.class);
System.out.println(ann);
//获取注解中的值
System.out.println(ann.value());
}
}
@SuppressWarnings("serial")
@MyAnnotation("tableName")
class MyArrayList extends ArrayList<String>{
public String str;
@SuppressWarnings("unused")
private MyArrayList(String str){
this.str = str;
}
public MyArrayList(){}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotation{
public String value() default "";
}
Method类的使用
package com.itheima.hightech;
import java.lang.reflect.Method;
public class MethodDemo {
public static void main(String[] args) throws Exception{
String str = MethodDemo.getObject("aaa");
System.out.println(str);
//在这里本想使用String.class的,但是好像泛型T 只能用Object代表
Method m = MethodDemo.class.getMethod("getObject", Object[].class);
//通过Method调用方法
//在这里可以使用两种方式:new Object[]{new Object[]{"ss","2dd"}}
//原因是:可变参数的方法调用时,如果是数组,会自动拆解的
System.out.println(m.invoke(null, (Object)new Object[]{"ss","dd"}));
//得到参数类型
Class<?>[] clses = m.getParameterTypes();
for (Class<?> class1 : clses) {
System.out.println(class1);
}
//得到所有的方法
Method[] methods = MethodDemo.class.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//得到方法的返回值
Class<?> cls = m.getReturnType();
System.out.println(cls);
}
public static <T> T getObject(T... ts){
return ts[0];
}
}
上面例子中需要重点注意的是:
//在这里本想使用String.class的,但是好像泛型T 只能用Object代表
Method m = MethodDemo.class.getMethod("getObject", Object[].class);
//通过Method调用方法
//在这里可以使用两种方式:new Object[]{new Object[]{"ss","2dd"}}
//原因是:可变参数的方法调用时,如果是数组,会自动拆解的
System.out.println(m.invoke(null, (Object)new Object[]{"ss","dd"}));
Field类的使用
这是我在工作中使用Field类写的一个工具类
package com.longtime.app.ixin.mgr.utils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
/**
*
* @author 陈克锋
*
*/
public class DBUtils {
private static final Logger logger = LoggerFactory.getLogger(DBUtils.class);
/**
* 例如:一个JavaBean Person [person为传递进来的Person对象] 字段有 private String id,private String name <br>
* 对应表为 person 字段为 id,name
* 忽略字段为 name
* 生成的sql 语句为 insert into 'tableName' (id) value (?)
* 生成的insertVals 为List 类型 [person.getId()]
*
* @param entity service传递进来需要保存的对象
* @param tableName 表名
* @param ignoreColumns 那些字段不需要插入
* @return sql 生成的sql语句
* insertVals 生成的体替代?的字段值
* timeConsuming 耗时长
*/
public static <T> Map<String,Object> getInsertSql(T entity,String tableName,List<String> ignoreColumns){
Map<String,Object> map = new HashMap<String, Object>();
List<Object> insertVals = new ArrayList<Object>();
long statTime = System.currentTimeMillis();
try{
StringBuffer sqlBuffer = new StringBuffer("insert into ");
sqlBuffer.append(tableName).append(" (");
StringBuffer valueBuffer = new StringBuffer(" value (");
Field[] fields = entity.getClass().getDeclaredFields();
PropertyDescriptor descriptor = null;
for (Field field : fields) {
if(ignoreColumns!=null && ignoreColumns.contains(field.getName())){
continue;
}
descriptor = new PropertyDescriptor(field.getName(), entity.getClass());
sqlBuffer.append(field.getName()).append(',');
valueBuffer.append('?').append(',');
insertVals.add(descriptor.getReadMethod().invoke(entity));
}
sqlBuffer.replace(sqlBuffer.length()-1, sqlBuffer.length(), ")").append((valueBuffer.replace(valueBuffer.length()-1, valueBuffer.length(), ")")));
map.put("sql", sqlBuffer.toString());
map.put("insertVals", insertVals);
map.put("timeConsuming", System.currentTimeMillis()-statTime);
}catch(Exception e){
logger.debug("get insert sql failure.");
}
return map;
}
/**
*
* @param entity
* @param tableName
* @param ignoreColumns
* @param whereColumn 条件字段
* @return sql ,updateVals ,timeConsuming
*/
public static <T> Map<String, Object> getUpdateSql(T entity,
String tableName, List<String> ignoreColumns,String whereColumn) {
Map<String,Object> map = new HashMap<String, Object>();
List<Object> updateVals = new ArrayList<Object>();
long statTime = System.currentTimeMillis();
try{
StringBuffer sqlBuffer = new StringBuffer("update ");
sqlBuffer.append(tableName).append(" set");
Field[] fields = entity.getClass().getDeclaredFields();
PropertyDescriptor descriptor = null;
for (Field field : fields) {
if(ignoreColumns!=null && ignoreColumns.contains(field.getName())){
continue;
}
descriptor = new PropertyDescriptor(field.getName(), entity.getClass());
sqlBuffer.append(" ").append(field.getName()).append("=").append("?,");
updateVals.add(descriptor.getReadMethod().invoke(entity));
}
map.put("sql", sqlBuffer.replace(sqlBuffer.length()-1, sqlBuffer.length(), " where ").append(whereColumn).append("=?").toString());
descriptor = new PropertyDescriptor(whereColumn, entity.getClass());
updateVals.add(descriptor.getReadMethod().invoke(entity));
map.put("updateVals", updateVals);
map.put("timeConsuming", System.currentTimeMillis()-statTime);
}catch(Exception e){
e.printStackTrace();
logger.debug("get insert sql failure.");
}
return map;
}
/**
* 得到记录总数
* @param sql
* @return
*/
public static int getCount(String sql,JdbcTemplate jdbcTemplate,Object...reqVal){
List<Integer> list = jdbcTemplate.query(sql, reqVal ,new RowMapper<Integer>(){
@Override
public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getInt(1);
}
});
if(list!=null && list.size()>0){
return list.get(0);
}
return 0;
}
/**
*
* @param obj
* @param sql
* @param jdbcTemplate
* @param params
* @return
*/
@SuppressWarnings("unchecked")
public static <T> List<T> queryList(final T obj,String sql,JdbcTemplate jdbcTemplate,Object...params){
try {
return jdbcTemplate.query(sql, params,new RowMapper<T>(){
@Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
try{
Constructor<T> c = (Constructor<T>)obj.getClass().getConstructor();
T returnObj = c.newInstance();
Field[] fields = obj.getClass().getDeclaredFields();
PropertyDescriptor descriptor = null;
for (Field field : fields) {
descriptor = new PropertyDescriptor(field.getName(), returnObj.getClass());
descriptor.getWriteMethod().invoke(returnObj, rs.getObject(field.getName()));
}
return returnObj;
}catch(Exception e){
throw new RuntimeException("error.");
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args)throws Exception {
queryList(new String(), null, null);
}
}
本来想使用BeanUtils工具类进行field的取值操作与赋值操作,但是测试的时候发现效率很低,就以insert语句的组成来说,就耗费了700ms,使用PropertyDescriptor类进行操作时,效率有很大的提升,耗时大概在2ms左右。
在下篇准备写一个通用DAO与通用Service GenericDao,GenericService
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net