黑马程序员_Java基础加强_反射

来源:互联网 发布:网络购物纠纷立案 编辑:程序博客网 时间:2024/05/22 09:44

---------------------- 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);}}//获取类上的所有AnnotationAnnotation[] anns = list.getClass().getAnnotations();for (Annotation ann : anns) {System.out.println(ann);}//得到某一个annotationMyAnnotation 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>(){@Overridepublic 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>(){@Overridepublic 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


0 0