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

上一节总结了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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值