java反射原理制作对象打印工具

主要运用java反射原理,格式化输出java对象属性值,特别是list 和map。

MyTestUtil.java

package utils;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 这个类是方便控制台输出object,主要应用java反射机制。 因为考虑到使用性和美观性,没有使用无限递归。
 * 而是在toStr方法中加入一个boolean recursion ,是否递归。
 * 当然我们也可以将boolean recursion换成int recursion,控制递归次数。
 * 其实就我使用经验来看,复杂数据toString,用json工具转化成json输出是一个不错的方式。
  //这是我用的方式,boolean recursion是否递归
  public static int add(int i,boolean recursion){
    sum+=i;
    if(recursion)
      add(i, false);
    return sum;
  }
  //也可以这样,int recursion表示递归次数
  public static int add(int i,int recursion){
    sum+=i;
    if(recursion>0){
      recursion--;
      add(i, recursion);
    }
    return sum;
  }
 *
 *
 * @author klguang
 *
 */

public class MyTestUtil {
  static final String SPLIT_LINE = "=";// 分割线
  static final String MY_SIGN = "KLG_print";//默認標記
  private static String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

  /**
   * 将集合类型toSring方法
   * @param object
   * @param recursion
   *      是否递归
   * @return
   */
  private static String collectionToStr(Object object, boolean recursion) {
    if (object == null)
      return "null";
    Object[] a = null;
    // 将集合类型转换成数组类型
    if (isArrayType(object))
      a = (Object[]) object;
    else
      a = ((Collection) object).toArray();
    if (isSimpleArr(a) || !recursion)
      return Arrays.toString(a);
    else
      return complexArrToStr(a);
  }

  /**
   * Arrays有toString方法,但是对象内容太多,在一行显示 还有就是没有显示index信息
   */
  private static String complexArrToStr(Object[] a) {
    if (a == null)
      return "null";

    int iMax = a.length - 1;
    if (iMax == -1)
      return "[]";

    StringBuilder b = new StringBuilder();
    for (int i = 0;; i++) {
      String value = objToStr(a[i], false);
      b.append("[" + i + "]" + " -> " + value);
      if (i == iMax)
        return b.toString();
      b.append(", \r\n");
    }
  }

  /**
   * map类型toString方法
   *
   * @param map
   * @param recursion
   *      是否递归
   * @return
   */
  private static String mapToStr(Map<String, Object> map, boolean recursion) {
    if (map == null)
      return "null";
    if (isSimpleMap(map) || !recursion)
      return simpleMapToStr(map);
    else
      return complexMapToStr(map, true);
  }

  /**
   * map的value是简单类型的,复制Map.toString,我给它加了换行10个换行
   *
   * @param map
   * @return
   */
  private static String simpleMapToStr(Map map) {
    Iterator<Entry<String, Object>> i = map.entrySet().iterator();
    if (!i.hasNext())
      return "{}";

    StringBuilder sb = new StringBuilder();
    sb.append('{');
    for (int t = 1;; t++) {
      Entry<String, Object> e = i.next();
      sb.append(e.getKey()).append(" = ").append(e.getValue());
      if (!i.hasNext())
        return sb.append('}').toString();
      sb.append(',').append(' ');
      if (t % 10 == 0 && t != 0)
        sb.append("\r\n ");
    }
  }

  private static String complexMapToStr(Map map, boolean recursion) {
    Iterator<Entry<String, Object>> i = map.entrySet().iterator();
    if (!i.hasNext())
      return "{}";
    StringBuilder sb = new StringBuilder();
    sb.append("{\r\n");
    for (int t = 1;; t++) {
      Entry<String, Object> e = i.next();
      String key = String.valueOf(e.getKey());
      Object value = e.getValue();
      sb.append(indent(2," ")).append(key).append(" = ");
      if (isSimpleType(value) || !recursion)
        sb.append(String.valueOf(value));
      else
        sb.append(objToStr(value, false));
      if (!i.hasNext())
        return sb.append("\r\n}").toString();
      sb.append(',').append("\r\n");
    }
  }

  /**
   *
   *
   * @param object
   * @param recursion
   *      是否要递归
   * @return
   */
  private static String beanToStr(Object object, boolean recursion) {
    if (object == null)
      return "null";
    Class clazz = object.getClass();
    StringBuilder sb = new StringBuilder();
    //返回源代码中给出的底层类的简称
    sb.append(clazz.getSimpleName()).append("[");
    Field[] fields = sortFieldByType(clazz.getDeclaredFields());
    int iMax = fields.length - 1;
    if (iMax == -1)
      return sb.append("]").toString();
    for (int i = 0;; i++) {
      Field field = fields[i];
      field.setAccessible(true);// 设置些属性是可以访问的
      String name = field.getName();// 取得field的名称
      if (name.equals("serialVersionUID"))
        continue;
      try {
        Object value = field.get(object);// 得到此属性的值
        if (isSimpleType(value) || !recursion)
          sb.append(name + " = " + String.valueOf(value));
        else
          sb.append("\r\n" + indent(clazz.getSimpleName().length() + 2," ")
              + objToStr(value, false) + "\r\n");
      } catch (Exception e) {
        e.printStackTrace();
      }
      if (i == iMax)
        return sb.append("]").toString();
      sb.append(",");
    }
  }

  private static String indent(int length,String sign) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < length; i++) {
      sb.append(sign);
    }
    return sb.toString();
  }

  private static boolean isSimpleType(Object obj) {
    if (obj == null)
      return true;
    else {
      Class objectClass = obj.getClass();
      return isSimpleType(objectClass);
    }
  }

  /**
   *
   * @param objectClass
   *      用obj.getClass()取得
   * @return
   */
  private static boolean isSimpleType(Class objectClass) {
    if (objectClass == boolean.class || objectClass == Boolean.class
        || objectClass == short.class || objectClass == Short.class
        || objectClass == byte.class || objectClass == Byte.class
        || objectClass == int.class || objectClass == Integer.class
        || objectClass == long.class || objectClass == Long.class
        || objectClass == float.class || objectClass == Float.class
        || objectClass == char.class || objectClass == Character.class
        || objectClass == double.class || objectClass == Double.class
        || objectClass == String.class) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * Method isCollectionType
   *
   * @param obj
   *      Object
   * @return boolean
   */
  private static boolean isCollectionType(Object obj) {
    if (obj == null)
      return false;
    return (obj.getClass().isArray() || (obj instanceof Collection));
  }

  private static boolean isArrayType(Object obj) {
    if (obj == null)
      return false;
    return (obj.getClass().isArray());
  }

  private static boolean isMapType(Object obj) {
    if (obj == null)
      return false;
    return (obj instanceof Map);
  }

  private static boolean isDateType(Object obj){
    if(obj==null)
      return false;
    return (obj instanceof Date);
  }

  private static boolean isBeanType(Object obj) {
    if (isSimpleType(obj) || isCollectionType(obj) || isMapType(obj))
      return false;
    else
      return true;
  }

  private static boolean isSimpleArr(Object[] a) {
    if (a == null || a.length < 1)
      return true;
    boolean flag = true;
    for (Object o : a) {
      if (!isSimpleType(o)) {
        flag = false;
        break;
      }
    }
    return flag;
  }

  private static boolean isSimpleMap(Map map) {
    if (map == null)
      return true;
    Iterator<Entry<String, Object>> i = map.entrySet().iterator();
    boolean flag = true;
    while (i.hasNext()) {
      Entry<String, Object> e = i.next();
      if (!isSimpleType(e.getValue())) {
        flag = false;
        break;
      }
    }
    return flag;
  }

  /***
   * 将简单类型排在前面
   * @param fields
   * @return
   */

  public static Field[] sortFieldByType(Field[] fields) {
    for (int i = 0; i < fields.length; i++) {
      if (isSimpleType(fields[i].getType()))
        continue;// fields[i]是简单类型不管
      // fields[i]是复杂类型
      // int j = i+1,从fields[i]之后开始比较
      for (int j = i + 1; j < fields.length; j++) {
        Field fieldTmp = null;
        if (isSimpleType(fields[j].getType())) {// 与后面的第一个简单类型交互
          fieldTmp = fields[i];
          fields[i] = fields[j];
          fields[j] = fieldTmp;
          break; // 后面的循环,是没有意义de
        }
      }
    }
    return fields;
  }

  /**
   * 这个方法是递归方法,并且并多个地方调用,考虑到循环引用和显示格式, boolean recursion取得确保递归可以被终止。
   *
   * @param object
   * @param recursion
   *      是否需要更深一层显示
   * @return
   */
  private static String objToStr(Object object, boolean recursion) {
    if (object == null)
      return "null";
    object.toString();
    if(isDateType(object))
      return new SimpleDateFormat(DATE_FORMAT).format((Date)object);
    else if (isBeanType(object))
      return beanToStr(object, recursion);
    else if (isCollectionType(object))
      return collectionToStr(object, recursion);
    else if (isMapType(object))
      return mapToStr((Map) object, recursion);
    else
      return String.valueOf(object);
  }

  public static String objToStr(Object obj) {
    return objToStr(obj, true);
  }

  private static void print(Object obj,String sign,String content) {
    String begin=indent(15, SPLIT_LINE) + " " +obj.getClass().getSimpleName()
      + " >> " + sign + " " + indent(10, SPLIT_LINE);
    int length=(begin.length()-sign.length()-5)/2;

    String end=indent(length, SPLIT_LINE)+ " " + sign + " " + indent(length, SPLIT_LINE);
    System.out.println(begin+"\r\n"+content+"\r\n"+end);

  }
  public static void print(Object obj){
    print(obj,MY_SIGN,objToStr(obj));
  }
  public static void printWithSign(String sign, Object obj) {
    print(obj, sign,objToStr(obj));
  }
}

不过呢上面代码太繁琐了,没有考虑多种类型嵌套的问题。
数组类型强转会报ClassCastException 。
平常打日志就用log4j写个工具方法 比上面这个清晰明了多了。

public static void debug(String message,Object o){
int count=0;
if(o==null){
LOGGER.debug(chain(message,": null"));
return;
}
if(o.getClass().isArray()){
for(int i=0,len=Array.getLength(o);i<len;i++){
debug(chain(message,"-[",i,"]"),Array.get(o, i));
}
}else if(o instanceof Map){
Entry<?,?> e;
for(Iterator<?> it=((Map<?,?>)o).entrySet().iterator();it.hasNext();){
e=(Entry<?,?>) it.next();
debug(chain(message,"-[K:",e.getKey(),"]"),e.getValue());
}
}else if(o instanceof Iterable){
for(Iterator<?> it=((Iterable<?>) o).iterator();it.hasNext();){
count++;
debug(chain(message,"-[",count,"]"),it.next());
}
}else{
LOGGER.debug(chain(message,":",o));
}
}
(0)

相关推荐

  • Java反射之类的实例对象的三种表示方式总结

    如下所示: <span style="font-size:14px;">package com.imooc.reflect; public class ClassDemo1 { public static void main(String[] args) { //Foo的实例对象如何表示 Foo foo1 = new Foo();//foo1就表示出来了 //Foo这个类,也是一个实例对象,Class类的实例对象,如何表示呢. //任何一个类都是Class的实例对象,这个实

  • Java 用反射设置对象的属性值实例详解

    Java 用反射设置对象的属性值实例详解 /** * 用反射设置对象的属性值 * @param obj 需要設置值的對象 * @param fieldName 需要設置值的屬性 * @param value 需要设置的值 * @return 设置值后的对象 */ private Object invoke(Object obj, String fieldName, Object value) { String firstWord = fieldName.substring(0, 1).toUpp

  • Java的反射机制---动态调用对象的简单方法

    唉!我还真是在面试中学习新东东啊,一个公司刚刚给了个测试,不过我很奇怪的是为什么web developer的职位居然考java的反射机制题,不过学习研究一下反射机制对我来说是件好事啦! 先说说什么是java反射机制吧,在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这 种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.主要功能:在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对 象:在运行时判断任意一个

  • Java利用反射自动封装成实体对象的方法

    本文实例讲述了Java利用反射自动封装成实体对象的方法.分享给大家供大家参考.具体分析如下: 利用此方法的时候需要传递的参数的名称,必须以行号结尾,去掉行号就是属性名称,比如页面传递name+rowNo,那么实体对象的属性名应该为name.代码如下 复制代码 代码如下: //获取页面数据,自动封装成bean对象 public List getObjectList(Class clazz,String[] rowNos) throws Exception{         List objList

  • Java反射之通过反射获取一个对象的方法信息(实例代码)

    以下代码为一个工具类 package com.imooc.reflect; import java.lang.reflect.Method; public class ClassUtil { public static void printClassMessage(Object obj){ //要获取类的信息,首先要获取类的类类型 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型 //获取类的名称 System.out.println("类的名称

  • java基于反射得到对象属性值的方法

    本文实例讲述了java基于反射得到对象属性值的方法.分享给大家供大家参考,具体如下: 通过反射机制得到对象中的属性和属性值 在对象中private没问题,在别的类中有时会报异常.下面的例子是在本对象中 /** * Engine entity. @author MyEclipse Persistence Tools */ public class Engine implements java.io.Serializable { // Fields private Long engineId; pr

  • Java通过反射机制动态设置对象属性值的方法

    /** * MethodName: getReflection<br> * Description:解析respXML 在通过反射设置对象属性值 * User: liqijing * Date:2015-7-19下午12:42:55 * @param clzzName * @param respXML * @return * @throws ClassNotFoundException * @throws DocumentException * @throws IllegalArgumentE

  • java反射原理制作对象打印工具

    主要运用java反射原理,格式化输出java对象属性值,特别是list 和map. MyTestUtil.java package utils; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.Iterator; import

  • 精致小巧的java相册制作方法

    本文实例为大家分享了java相册制作方法,供大家参考,具体内容如下 注: 1)html上的图片是静态指定的.当更新了新的图片时必须手工更新.所以使用Servlet读取本地images中的所有图片,动态显示给用户. 2)如果存在中文名的图片,由于get方式无法直接传递中文,会导致出错. 主页面–index.jsp <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"

  • 探讨Java验证码制作(上篇)

    相信大家对验证码这玩意不会陌生,无论是申请账号还是某些情况下登录时都会要求输入验证码.经过统计,验证码一次验证就成功通过的概率是90%,并不高,那么很多人对于这种降低用户体验度的设计肯定会怀疑他的必要性,但黑格尔说过:凡是合乎理性的东西都是现实的:凡是现实的东西都是合乎理性的.接下来我们来了解一下验证码. 验证码是一种区别用户是计算机还是人的公共全自动程序,他被用于防止恶意破解密码.刷票.论坛灌水,防止黑客通过暴力破解方式不断地登录,应用于银行.社区.论坛.投票系统等等. 废话不多说我们来看看我

  • java之File对象对文件的操作常用的几个方法(推荐)

    File对象是对文件操作最常用的类,平常工作总用的很多,贴出来了几个我工作常用的几个方法.简单总结了下 直接上代码: //构建文件对象 File file=new File("E:/android_demo/a"); File fileTest=new File("E:/android_demo/a/test.mp3"); //获取文件的父路径 File f=file.getParentFile(); System.out.println("f==&quo

  • java编程 中流对象选取规律详解

    实例如下: import java.io.*; public class TransStreamDemo2 { /** * 流操作的基本规律 * 1. * 源,键盘录入 * 目的.控制台 * 2. * 需求:想把键盘录入的数据存储到一个文件中. * 源:键盘 * 目的:文件(FileoutputStream可以操作文件) * 3. * 需求:想把一个文件的数据打印到控制台上 * 源:某个文件 * 目的:控制台 * * * 流操作的基本规律 * 最痛苦的是流对象很多不知道用哪个 * * 通过两个明

  • java 虚拟机中对象访问详解

    java 虚拟机中对象访问详解 对象访问会涉及到Java栈.Java堆.方法区这三个内存区域. 如下面这句代码: Object objectRef = new Object(); 假设这句代码出现在方法体中,"Object objectRef" 这部分将会反映到Java栈的本地变量中,作为一个reference类型数据出现.而"new Object()"这部分将会反映到Java堆中,形成一块存储Object类型所有实例数据值的结构化内存,根据具体类型以及虚拟机实现的

  • Java IO流对象的序列化和反序列化实例详解

    Java-IO流 对象的序列化和反序列化 序列化的基本操作 1.对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化. 2.序列化流(ObjectOutputStream),writeObject 方法用于将对象写入输出流中: 反序列化流(ObjectInputStream),readObject 方法用于从输入流中读取对象. 3.序列化接口(Serializeable) 对象必须实现序列化接口,才能进行序列化,否则会出现异常.这个接口没有任何方法,只是一个标准. packag

  • 探讨Java验证码制作(下篇)

    接着上篇java验证码制作(上篇)给大家介绍有关java验证码的相关知识! 方法三: 用开源组件Jcaptcha实现,与Spring组合使用可产生多种形式的验证码,JCaptcha 即为Java版本的 CAPTCHA 项目,其是一个开源项目,支持生成图形和声音版的验证码,在生成声音版的验证码时,需要使用到 FreeTTS.而CAPTCHA 全称 Completely Automated Public Turing Test to Tell Computers and Humans Apart,最

  • Java中的对象流总结(必看篇)

    Java中可以通过对象流将一个序列化的对象保存到硬盘中,或者硬盘中读取一个对象.对象流的存储和读取包含以下几点内容: 1.所保存的对象必须实现Serializable接口. 2. 所保存的对象的属性也必须实现Serializable接口. 3. 最好要给该对象提供一个版本号,private static final long serialVersionId. 下面是一个对象流存储和读取一个对象的流程图: class Person implements Serializable { //实现序列化

  • JS自定义对象实现Java中Map对象功能的方法

    本文实例讲述了JS自定义对象实现Java中Map对象功能的方法.分享给大家供大家参考.具体分析如下: Java中有集合,Map等对象存储工具类,这些对象使用简易,但是在JavaScript中,你只能使用Array对象. 这里我创建一个自定义对象,这个对象内包含一个数组来存储数据,数据对象是一个Key,可以实际存储的内容!   这里Key,你要使用String类型,和Java一样,你可以进行一些增加,删除,修改,获得的操作. 使用很简单,我先把工具类给大家看下: 复制代码 代码如下: /**  *

随机推荐