反射应用之一---编写通用的toString()方法

来源:互联网 发布:win10网络不稳定 编辑:程序博客网 时间:2024/06/05 04:57

上一节总结了Java反射机制里涉及到的几个类和其用法,本节就应用这些类和方法实现一个通用的toString()方法。

要将一个对象toString,我们需要考虑到哪些方面呢?
1. 如果对象是一个数组,那么我们需要遍历其元素,然后将元素作为新的对象递归调用我们的toString方法;
2. 如果对象是个基本类型/字符串,那么可以直接返回其value;
3. 如果对象是个复杂对象,那么我们需要获取其所有的字段,然后遍历,如果该字段是基本类型/字符串,则直接返回其value,否则将每个字段作为新的对象递归调用我们的toString方法;
4. 不处理Map对象,因为其实现类都实现了toString方法。

实现如下:

package reflect;import java.lang.reflect.AccessibleObject;import java.lang.reflect.Array;import java.lang.reflect.Field;import java.lang.reflect.Modifier;import java.util.ArrayList;import java.util.List;/** * @author rambo.pan * 2016年10月10日 */public class ObjectAnalyzer {    private static final String NULL_STRING = "null";    private static final String VISITED_STRING = "...";    //该数组用来记录已解析过的对象类型    private List<Object> visited = new ArrayList<Object>();    /**     * 递归方法,object是个数组,则遍历其元素,递归调用该方法;否则是个类实例,则遍历其所有字段     * @param obj     * @return     */    public String toString(Object obj){        //如果对象为空,则返回null        if (obj == null) {            return NULL_STRING;        }      //如果对象已被处理过,则返回,针对于 A、B对象相互组合的情况,否则会循环递归,导致StackOverFlow        if (visited.contains(obj)) {            return VISITED_STRING;        }        visited.add(obj);        //获取对象的Class实例,同一个类的对象,共有一个相应的Class实例,在类被加载到虚拟机时就存储在方法区中了        Class<?> cl = obj.getClass();        //如果对象正好是String对象,则强转后直接返回        if (cl == String.class) {            return (String)obj;        }        //如果object是个数组,则遍历其元素,对元素进行toString(Object)递归调用        if (cl.isArray()) {            //获取数组的元素类型            String r = cl.getComponentType() + "[]{";            for (int i = 0; i < Array.getLength(obj); i++) {                if (i > 0) {                    r += ",";                }                //获取指定下标的数组元素                Object val = Array.get(obj, i);                //如果元素是原始/基本类型(Java共8种基本类型),则直接输出                if (cl.getComponentType().isPrimitive()) {                    r += val;                }else {//否则递归调用,直到其为原始类型                    r += toString(val);                }            }            //对数组元素遍历完成,返回。            return r + "}";        }        //object不是数组类型,首先获取其类型Name        String r = cl.getName();        //遍历object的所有字段,然后获取字段的Name和Value,之后再遍历其父类,直到遍历到父类为Object        do{            r += "[";            //获取object的所有字段,无论访问限制符是public还是private,但不包括其从父类继承来的字段            Field[] fields = cl.getDeclaredFields();            //设置字段的访问权限为可访问            AccessibleObject.setAccessible(fields, true);            for (Field field : fields) {                //忽略static属性                if (Modifier.isStatic(field.getModifiers())) {                    continue;                }                if (!r.endsWith("[")) {                    r += ",";                }                r += field.getName() + "=";                try{                    //获取字段类型和字段的值                    Class<?> t = field.getType();                    Object val = field.get(obj);                    //如果字段类型是原始类型,则直接输出;否则递归调用toString(Object)                    if (t.isPrimitive()) {                        r += val;                    }else {                        r += toString(val);                    }                }catch (Exception e) {                    e.printStackTrace();                }            }            //一个类型的字段遍历结束            r += "]";            //获取该类型的父类Class实例,然后继续该循环            cl = cl.getSuperclass();        }while(cl != null);        //类型遍历完成,返回object的字符串结果        return r;    }}
0 0