`
congjl2002
  • 浏览: 211618 次
  • 性别: Icon_minigender_1
  • 来自: 辽宁
社区版块
存档分类
最新评论

Apache Commons Lang 2.4 代码分析之ToStringStyle

阅读更多
  ToStringStyle对象代表的是一种输出的模式,它一般和ToStringBuilder结合使用,直接调用的机会不多,但是通过阅读它的代码,可以了解ToStringBuilder是如何进行对象的格式化输出的。
1.私有变量
boolean useFieldNames = true;是否使用字段名称
boolean useClassName = true;是否使用全路径类名
boolean useShortClassName = false;是否使用短类名
boolean useIdentityHashCode = true;是否使用惟一的哈希号
String contentStart = "[";String的开始标记
String contentEnd = "]";String的结束标记
boolean fieldSeparatorAtStart = false;是否在每个字段前加一个分隔符
boolean fieldSeparatorAtEnd = false;是否在每个字段后加一个分隔符
String fieldSeparator = ",";字段分隔符
String arrayStart = "{";数组开始标记
String arraySeparator = ",";数组成员分隔符
boolean arrayContentDetail = true;是否输出数组的细节
String arrayEnd = "}";数组结束标记
boolean defaultFullDetail = true;
String sizeStartText = "<size=";summary中描述对象size的开始标记
String sizeEndText = ">";ummary中描述对象size的结束标记
String summaryObjectStartText = "<";summary中描述对象本身的开始标记
String summaryObjectEndText = ">";summary中描述对象本身的结束标记

2.派生类
该对象有几种对象继承自该对象,派生类通过设置超类的一些私有属性(在构造函数中设置),达到输出的不同效果,有以下几种派生类:

2.1 DefaultToStringStyle和超类一致,没有任何限制。
显示效果:
  commons.lang.simples.Person@182f0db[name=John Doe,age=33,smoker=false]

2.2 NoFieldNameToStringStyle限制输出字段的名称,而只有值。
显示效果:
  commons.lang.simples.Person@182f0db[John Doe,33,false]
原理:
  this.setUseFieldNames(false);

2.3 ShortPrefixToStringStyle限制类名和哈希号的输出。
显示效果:
  Person[name=John Doe,age=33,smoker=false]
原理:
  this.setUseShortClassName(true);
  this.setUseIdentityHashCode(false);

2.4 SimpleToStringStyle仅输出字段内容,其它一律省略。
显示效果:
  John Doe,33,false
原理:
  this.setUseClassName(false);
  this.setUseIdentityHashCode(false);
  this.setUseFieldNames(false);
  this.setContentStart("");
  this.setContentEnd("");

2.5 MultiLineToStringStyle把每个字段单独占一行。
显示效果:
  commons.lang.simples.Person@182f0db[
    name=John Doe
    age=33
    smoker=false
  ]
原理:
  this.setContentStart("[");
  this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + "  ");
  this.setFieldSeparatorAtStart(true);
  this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]");

这几个类都以private static final class的形式出现,并作为ToStringStyle的内部类。该对象本身也声明了对应以上类的公共静态final对象(public static final ToStringStyle),如下所示。这样就可以方便的得到这几个派生类。
DefaultToStringStyle DEFAULT_STYLE
MultiLineToStringStyle MULTI_LINE_STYLE
NoFieldNameToStringStyle NO_FIELD_NAMES_STYLE
ShortPrefixToStringStyle SHORT_PREFIX_STYLE
SimpleToStringStyle SIMPLE_STYLE

3.输出开始和结束标记
ToStringStyle利用一组*Start和*End的一组方法,输出对象/对象内容/对象字段的开始和结束标记,这些方法第一个参数均为Buffer,即实际写入的StringBuffer对象。具体描述如下所示:
3.1 appendStart和appendEnd
appendStart输出一个对象时首先输出的部分。该对象作为参数传入。当对象不为空时,完成以下工作:
  利用appendClassName方法输出类名。
  利用appendIdentityHashCode方法输出该类的哈希号。
  利用appendContentStart方法输出内容开始的标记。
  如果需要“在开始加入字段分隔符”,则利用appendFieldSeparator方法加入字段分隔符。
appendEnd 输出一个对象时最后输出的部分。该对象作为参数传入。但没有实际业务用处(仅用于unregister)。
  如果不需要“在结束处加入字段分隔符”,则利用removeLastFieldSeparator方法去掉最后一个字段分隔符。
  利用appendContentEnd方法输出内容结束的标记。

3.2 appendContentStart和appendContentEnd
appendContentStart输出表示内容开始的标记,缺省为“[”。
appendContentEnd输出表示内容结束的标记,缺省为“]”。

3.3 appendFieldStart和appendFieldEnd
appendFieldStart 输出形如“fieldName=”的格式,其中=可以替换为别的内容。fieldName作为参数传入。
appendFieldEnd 输出字段分隔符,缺省为“,”。fieldName作为参数传入,但没有使用。

4.append方法
ToStringStyle提供了各种append方法,涵盖了单个对象,原始类型和数组三种形式。append方法的通用模式是把一个对象(变量为value,类型如前所述三种形式),作为一个字段(变量为fieldName)用StringBuffer对象(变量为buffer)进行输出。

4.1 对单个对象的append方法
4.1.1 该方法除了以上参数外,还利用fullDetail决定是否输出对象的细节。执行以下操作:
  利用appendFieldStart方法输出该字段的开始标记。
  如果对象为空,则利用appendNullText方法输出“数据为空”的标记,缺省为“<null>”。
  如果对象不为空,则利用appendInternal方法输出对象的内容,利用fullDetail控制输出detail或仅是summary。
  利用appendFieldEnd方法输出该字段的结束标记。

4.1.2 appendInternal方法实际输出对象的信息,detail或summary。参数同append方法。执行以下操作:
  如果value已经注册(实际上表示已经完整输出过一次)或者不是原始类型包裹类,则利用ObjectUtils的identityToString方法输出对象标示(形如java.lang.String@1e23的格式,其中1e23为十六进制的哈希号)。方法结束。
  否则,注册对象,根据value的类型(普通的集合类型和明确的数组使用instanceof关键字判断,Object类型使用 value.getClass().isArray()判断)利用appendDetail和appendSummary族(其中Collection和 Map使用appendSummarySize仅输出集合大小)的对应方法决定如何输出detail或summary。
  注销对象。方法结束。

4.1.3 集合类型的appendDetail族,参数为buffer,fieldName和对应类型的value(集合类型或数组)
Collection:直接使用buffer.append。
Map:直接使用buffer.append。
Object:直接使用buffer.append。
long[]执行以下操作:
  使用buffer.append写入arrayStart,缺省为“{”。
  遍历数组,从第二个开始,首先输出数组分隔符(缺省为“,”),然后使用原始类型的appendDetail族输出。
  使用buffer.append写入arrayEnd,缺省为“}”。
int[],short[],byte[],char[],double[],float[],boolean[]同上
Object[]执行以下操作:
  使用buffer.append写入arrayStart,缺省为“{”。
  遍历数组
    从第二个开始,首先输出数组分隔符(缺省为“,”)。
    如果对象为空,则利用appendNullText方法输出“数据为空”的标记。
    如果对象不为空,则利用appendInternal方法输出对象的内容,利用fullDetail控制输出detail或仅是summary。(实际上递归)
  使用buffer.append写入arrayEnd,缺省为“}”。

4.1.4 appendSummary族,参数为buffer,fieldName和对应类型的Value(数组,不包含Object类型),但fieldName无用
Object[]: 利用appendSummarySize输出数组的大小。
long[],int[],short[],byte[],char[],double[],float[],boolean[]同上

4.1.5 appendSummarySize,参数为buffer,fieldName和大小(变量为size),执行以下操作
  输出“描述大小”的文本的起始符,缺省值为“<size=”。
  输出大小。
  输出“描述大小”的文本的结束符,缺省值为“>”。

4.1.6 appendSummary,参数为buffer,fieldName和类型为Object的Value,执行以下操作
  输出“描述对象概况”的文本的起始符,缺省值为“<”。
  输出通过getShortClassName获得的该对象的短类型描述符。
  输出“描述对象概况”的文本的结束符,缺省值为“>”。

4.2 对原始类型的append方法
4.2.1 append方法把一个原始类型(value),作为一个字段(fieldName)进行输出。
long执行以下操作:
  利用appendFieldStart方法输出该字段的开始标记。
  利用原始类型的appendDetail族数据value的内容。
  利用appendFieldEnd方法输出该字段的结束标记。
int,short,byte,char,double,float,boolean同上

4.2.2 原始类型的appendDetail族,参数为buffer,fieldName和对应原始类型的value
long直接使用buffer.append。
int,short,byte,char,double,float,boolean同上

4.3 对数组类型的append方法
append方法把一个数组类型(array),作为一个字段(fieldName)进行输出,利用fullDetail决定是否输出对象的细节。
Object[]执行以下操作:
  利用appendFieldStart方法输出该字段的开始标记。
  如果array为空,则利用appendNullText方法输出“数据为空”的标记。
  如果不为空且要求输出细节,则利用集合类型的appendDetail数据数组。
  否则,则利用appendSummary输出Summary。
  利用appendFieldEnd方法输出该字段的结束标记。
long[],int[],short[],byte[],char[],double[],float[],boolean[]

5 其他一些公共和私有类
5.1 appendSupper方法输出超类的内容,实际上就是调用appendToString输出文本。

5.2 appendToString方法输出一个使用了相同Style输出的文本(toString)。执行以下操作(字符串不为空):
  找到toString的内容(在contentStart和contentEnd中间的内容)。
  如果存在,则取出该部分。如果在内容的开头有字段分隔符,则利用removeLastFieldSeparator方法去掉最后一个字段分隔符。这里注意只有在toString变量和当前使用相同的Style才可以。然后输出取出的部分,并利用appendFieldSeparator方法输出字段分隔符。

5.3 removeLastFieldSeparator方法是一个Protected方法,用于删除最后一个字段分隔符。算法是主字符串长度设为len,字段分隔符长度设为sepLen。定义变量match为true,在住字符串中从后向前遍历,如果主字符串的最后sepLen个字符和字段分隔符相同,则把主字符串长度设为len减去sepLen,由于主字符串以StringBuffer形式存在。如果在遍历过程中,发现某个字符不符,说明主字符串最后的部分不是一个字段分隔符,则什么都不做。

5.4 appendClassName方法输出对象(object)的类名,执行如下操作:
  如果允许使用类名(useClassName布尔值),且object不为空,则
    注册object
    如果使用短类名,则使用getShortClassName方法获得结果并输出。
    否则,使用object.getClass().getName()获得全路径类名,并输出。

5.5 appendIdentityHashCode方法输出对象(object)的哈希号,执行如下操作:
  如果允许使用哈希号,且object不为空,则
    注册object
    输出“@”
    利用System.identityHashCode获取哈希号,并转换为十六进制输出。

5.6 reflectionAppendArrayDetail方法输出类型为Object的数组(object),处理与object[]的appendDetail方法类似。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics