服务器之家

服务器之家 > 正文

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

时间:2020-03-08 15:40     来源/作者:hebedich

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

 MyTestUtil.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
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写个工具方法 比上面这个清晰明了多了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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));
}
}
标签:

相关文章

热门资讯

玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分 2019-06-21
男生常说24816是什么意思?女生说13579是什么意思?
男生常说24816是什么意思?女生说13579是什么意思? 2019-09-17
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意 2019-07-07
超A是什么意思 你好a表达的是什么
超A是什么意思 你好a表达的是什么 2019-06-06
华为nova5pro和p30pro哪个好 华为nova5pro和华为p30pro对比详情
华为nova5pro和p30pro哪个好 华为nova5pro和华为p30pro对比详情 2019-06-22
返回顶部