java反射原理制作对象打印工具
主要运用java反射原理,格式化输出java对象属性值,特别是list和map。
MyTestUtil.java
packageutils; importjava.lang.reflect.Field; importjava.text.SimpleDateFormat; importjava.util.Arrays; importjava.util.Collection; importjava.util.Date; importjava.util.Iterator; importjava.util.Map; importjava.util.Map.Entry; /** *这个类是方便控制台输出object,主要应用java反射机制。因为考虑到使用性和美观性,没有使用无限递归。 *而是在toStr方法中加入一个booleanrecursion,是否递归。 *当然我们也可以将booleanrecursion换成intrecursion,控制递归次数。 *其实就我使用经验来看,复杂数据toString,用json工具转化成json输出是一个不错的方式。 //这是我用的方式,booleanrecursion是否递归 publicstaticintadd(inti,booleanrecursion){ sum+=i; if(recursion) add(i,false); returnsum; } //也可以这样,intrecursion表示递归次数 publicstaticintadd(inti,intrecursion){ sum+=i; if(recursion>0){ recursion--; add(i,recursion); } returnsum; } * * *@authorklguang * */ publicclassMyTestUtil{ staticfinalStringSPLIT_LINE="=";//分割线 staticfinalStringMY_SIGN="KLG_print";//默認標記 privatestaticStringDATE_FORMAT="yyyy-MM-ddHH:mm:ss"; /** *将集合类型toSring方法 *@paramobject *@paramrecursion *是否递归 *@return */ privatestaticStringcollectionToStr(Objectobject,booleanrecursion){ if(object==null) return"null"; Object[]a=null; //将集合类型转换成数组类型 if(isArrayType(object)) a=(Object[])object; else a=((Collection)object).toArray(); if(isSimpleArr(a)||!recursion) returnArrays.toString(a); else returncomplexArrToStr(a); } /** *Arrays有toString方法,但是对象内容太多,在一行显示还有就是没有显示index信息 */ privatestaticStringcomplexArrToStr(Object[]a){ if(a==null) return"null"; intiMax=a.length-1; if(iMax==-1) return"[]"; StringBuilderb=newStringBuilder(); for(inti=0;;i++){ Stringvalue=objToStr(a[i],false); b.append("["+i+"]"+"->"+value); if(i==iMax) returnb.toString(); b.append(",\r\n"); } } /** *map类型toString方法 * *@parammap *@paramrecursion *是否递归 *@return */ privatestaticStringmapToStr(Map<String,Object>map,booleanrecursion){ if(map==null) return"null"; if(isSimpleMap(map)||!recursion) returnsimpleMapToStr(map); else returncomplexMapToStr(map,true); } /** *map的value是简单类型的,复制Map.toString,我给它加了换行10个换行 * *@parammap *@return */ privatestaticStringsimpleMapToStr(Mapmap){ Iterator<Entry<String,Object>>i=map.entrySet().iterator(); if(!i.hasNext()) return"{}"; StringBuildersb=newStringBuilder(); sb.append('{'); for(intt=1;;t++){ Entry<String,Object>e=i.next(); sb.append(e.getKey()).append("=").append(e.getValue()); if(!i.hasNext()) returnsb.append('}').toString(); sb.append(',').append(''); if(t%10==0&&t!=0) sb.append("\r\n"); } } privatestaticStringcomplexMapToStr(Mapmap,booleanrecursion){ Iterator<Entry<String,Object>>i=map.entrySet().iterator(); if(!i.hasNext()) return"{}"; StringBuildersb=newStringBuilder(); sb.append("{\r\n"); for(intt=1;;t++){ Entry<String,Object>e=i.next(); Stringkey=String.valueOf(e.getKey()); Objectvalue=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()) returnsb.append("\r\n}").toString(); sb.append(',').append("\r\n"); } } /** * * *@paramobject *@paramrecursion *是否要递归 *@return */ privatestaticStringbeanToStr(Objectobject,booleanrecursion){ if(object==null) return"null"; Classclazz=object.getClass(); StringBuildersb=newStringBuilder(); //返回源代码中给出的底层类的简称 sb.append(clazz.getSimpleName()).append("["); Field[]fields=sortFieldByType(clazz.getDeclaredFields()); intiMax=fields.length-1; if(iMax==-1) returnsb.append("]").toString(); for(inti=0;;i++){ Fieldfield=fields[i]; field.setAccessible(true);//设置些属性是可以访问的 Stringname=field.getName();//取得field的名称 if(name.equals("serialVersionUID")) continue; try{ Objectvalue=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(Exceptione){ e.printStackTrace(); } if(i==iMax) returnsb.append("]").toString(); sb.append(","); } } privatestaticStringindent(intlength,Stringsign){ StringBuildersb=newStringBuilder(); for(inti=0;i<length;i++){ sb.append(sign); } returnsb.toString(); } privatestaticbooleanisSimpleType(Objectobj){ if(obj==null) returntrue; else{ ClassobjectClass=obj.getClass(); returnisSimpleType(objectClass); } } /** * *@paramobjectClass *用obj.getClass()取得 *@return */ privatestaticbooleanisSimpleType(ClassobjectClass){ 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){ returntrue; }else{ returnfalse; } } /** *MethodisCollectionType * *@paramobj *Object *@returnboolean */ privatestaticbooleanisCollectionType(Objectobj){ if(obj==null) returnfalse; return(obj.getClass().isArray()||(objinstanceofCollection)); } privatestaticbooleanisArrayType(Objectobj){ if(obj==null) returnfalse; return(obj.getClass().isArray()); } privatestaticbooleanisMapType(Objectobj){ if(obj==null) returnfalse; return(objinstanceofMap); } privatestaticbooleanisDateType(Objectobj){ if(obj==null) returnfalse; return(objinstanceofDate); } privatestaticbooleanisBeanType(Objectobj){ if(isSimpleType(obj)||isCollectionType(obj)||isMapType(obj)) returnfalse; else returntrue; } privatestaticbooleanisSimpleArr(Object[]a){ if(a==null||a.length<1) returntrue; booleanflag=true; for(Objecto:a){ if(!isSimpleType(o)){ flag=false; break; } } returnflag; } privatestaticbooleanisSimpleMap(Mapmap){ if(map==null) returntrue; Iterator<Entry<String,Object>>i=map.entrySet().iterator(); booleanflag=true; while(i.hasNext()){ Entry<String,Object>e=i.next(); if(!isSimpleType(e.getValue())){ flag=false; break; } } returnflag; } /*** *将简单类型排在前面 *@paramfields *@return */ publicstaticField[]sortFieldByType(Field[]fields){ for(inti=0;i<fields.length;i++){ if(isSimpleType(fields[i].getType())) continue;//fields[i]是简单类型不管 //fields[i]是复杂类型 //intj=i+1,从fields[i]之后开始比较 for(intj=i+1;j<fields.length;j++){ FieldfieldTmp=null; if(isSimpleType(fields[j].getType())){//与后面的第一个简单类型交互 fieldTmp=fields[i]; fields[i]=fields[j]; fields[j]=fieldTmp; break;//后面的循环,是没有意义de } } } returnfields; } /** *这个方法是递归方法,并且并多个地方调用,考虑到循环引用和显示格式,booleanrecursion取得确保递归可以被终止。 * *@paramobject *@paramrecursion *是否需要更深一层显示 *@return */ privatestaticStringobjToStr(Objectobject,booleanrecursion){ if(object==null) return"null"; object.toString(); if(isDateType(object)) returnnewSimpleDateFormat(DATE_FORMAT).format((Date)object); elseif(isBeanType(object)) returnbeanToStr(object,recursion); elseif(isCollectionType(object)) returncollectionToStr(object,recursion); elseif(isMapType(object)) returnmapToStr((Map)object,recursion); else returnString.valueOf(object); } publicstaticStringobjToStr(Objectobj){ returnobjToStr(obj,true); } privatestaticvoidprint(Objectobj,Stringsign,Stringcontent){ Stringbegin=indent(15,SPLIT_LINE)+""+obj.getClass().getSimpleName() +">>"+sign+""+indent(10,SPLIT_LINE); intlength=(begin.length()-sign.length()-5)/2; Stringend=indent(length,SPLIT_LINE)+""+sign+""+indent(length,SPLIT_LINE); System.out.println(begin+"\r\n"+content+"\r\n"+end); } publicstaticvoidprint(Objectobj){ print(obj,MY_SIGN,objToStr(obj)); } publicstaticvoidprintWithSign(Stringsign,Objectobj){ print(obj,sign,objToStr(obj)); } }
不过呢上面代码太繁琐了,没有考虑多种类型嵌套的问题。
数组类型强转会报ClassCastException。
平常打日志就用log4j写个工具方法比上面这个清晰明了多了。
publicstaticvoiddebug(Stringmessage,Objecto){ intcount=0; if(o==null){ LOGGER.debug(chain(message,":null")); return; } if(o.getClass().isArray()){ for(inti=0,len=Array.getLength(o);i<len;i++){ debug(chain(message,"-[",i,"]"),Array.get(o,i)); } }elseif(oinstanceofMap){ Entry<?,?>e; for(Iterator<?>it=((Map<?,?>)o).entrySet().iterator();it.hasNext();){ e=(Entry<?,?>)it.next(); debug(chain(message,"-[K:",e.getKey(),"]"),e.getValue()); } }elseif(oinstanceofIterable){ for(Iterator<?>it=((Iterable<?>)o).iterator();it.hasNext();){ count++; debug(chain(message,"-[",count,"]"),it.next()); } }else{ LOGGER.debug(chain(message,":",o)); } }