apache commons lang 3.2(一)创建者模式部分

近段时间,对apache commons lang的源码做了深入的了解,在此把一些见解与大家分享。

首先我选择了大部分框架还依赖的3.2版本而不是最新的3.4版本进行源码的研读,今天就简介一下commons lang的创建者模式部分。

首先我们来看一下该模块类调用关系:

创建者模式部分主要是使用创建者模式完成一些Object类中的共用方法,比如说toString()方法、equals()方法、hashCode()方法等。其出彩之处在于使用了创建者模式使其功能的扩展十分灵活,并且通过反射获取实体字段也让功能更加便捷。

大体来说创建者模式部分分为Builder接口、ToString部分、Compare部分、Equals部分。

Builder接口:

org.apache.commons.lang3.builder.Builder

Builder接口是设计来指定一个类作为创建者模式的构建对象的。创建者类有创建和配置对象或结果的能力,它分多步进行构造,或进行复合组成。

Builder接口定义了一个build()方法,每个实现了都必须实现。该方法的返回结果在创建操作执行完毕之后应该是配置完成的。

此处的最佳实践是该方法提供用于配置的对象或者在执行创建时返回一个创建者的引用使一套配置可多次创建。

创建者案例:

class FontBuilder implements Builder<Font> {

private Font font;

public FontBuilder(String fontName) {

this.font = new Font(fontName, Font.PLAIN, 12);

}

public FontBuilder bold() {

this.font = this.font.deriveFont(Font.BOLD);

return this; // Reference returned so calls can be chained

}

public FontBuilder size(float pointSize) {

this.font = this.font.deriveFont(pointSize);

return this; // Reference returned so calls can be chained

}

// Other Font construction methods

public Font build() {

return this.font;

}

}

创建者使用案例:

Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()

.size(14.0f)

.build();

ToString部分:

org.apache.commons.lang3.builder.ToStringStyle

该类为ToStringBuilder控制字符串格式的控制器。其最重要的接口Builder是由ToStringBuilder另外实现的。

该类内部定义了许多使用单例模式的默认StringStyle内部类。因此用户无需实例化新style。用户应用程序使用该类中预定义的各种常量即可。如果用户希望自定义style只需使用StandardToStringStyle即可。但该类实现了大部分style因此无需再创建子类。

如果需要,子类可按需重写或多或少该类中的方法。每一个对象类型(从基本数据类型到对象数据类型,甚至数组)都有它自身的输出方法。大部分有两种输出方法,一种是详情,一种是概要。

例如,数组类的详情基础方法会输出整个数组,然而概要方法仅输出数组长度。

如果你想格式化输出一个已知的对象,例如时间,你必须创建一个子类并重写方法。

public class MyStyle extends ToStringStyle {

protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {

if (value instanceof Date) {

value = new SimpleDateFormat("yyyy-MM-dd").format(value);

}

buffer.append(value);

}

}

该类只是处理由ToStringBuilder传入的单个字段的显示样式。

其内部主要实现了弱引用,以免在生成字符串的过程中循环引用,对象无法回收。在处理对象内容时其将内容分为前后两部分,前部分包括类名以及哈希码,对应start部分;后部分这是传入的字段以及值了。后部分主要通过appendInternal()进行处理,然后其调用底层具体方法加入到字符串中。

该类还通过调用ClassUtils.getShortClassName来获取类短名。

该类还通过调用ObjectUtils.identityToString来将内存地址哈希码变为字符串形式。

org.apache.commons.lang3.builder.ToStringStyle#DefaultToStringStyle

服务于ToStringBuilder来创建toString方法。

该类使用单例模式,因此用户无需实例化新对象。

一旦实例化,就会存在于内存中,供用户进行调用。

该类实现了[name=John Doe,age=33,smoker=false]样式的输出

org.apache.commons.lang3.builder.ToStringStyle#NoFieldNameToStringStyle

服务于ToStringBuilder来创建toString方法。

该类使用单例模式,因此用户无需实例化新对象。

一旦实例化,就会存在于内存中,供用户进行调用。

该类实现的样式不显示字段名。

org.apache.commons.lang3.builder.ToStringStyle#ShortPrefixToStringStyle

服务于ToStringBuilder来创建toString方法。

该类使用单例模式,因此用户无需实例化新对象。

一旦实例化,就会存在于内存中,供用户进行调用。

该类实现的样式类名显示为短名。

org.apache.commons.lang3.builder.ToStringStyle#MultiLineToStringStyle

服务于ToStringBuilder来创建toString方法。

该类使用单例模式,因此用户无需实例化新对象。

一旦实例化,就会存在于内存中,供用户进行调用。

该类实现了每个字段显示一行的样式。

该类使用SystemUtils.LINE_SEPARATOR获取系统的行分隔符,以提高可移植性。

org.apache.commons.lang3.builder.StandardToStringStyle

服务于ToStringBuilder来创建toString方法。

该类使用单例模式,因此用户无需实例化新对象。

一旦实例化,就会存在于内存中,供用户进行调用。

如果用户希望自定义样式,可继承该类进行扩展。

org.apache.commons.lang3.builder.ToStringBuilder

当重写Object.toString()方法时,可用该类进行辅助实现。

该类可为任何类或对象创建良好且一致的toString()方法。该类通过以下过程简化操作:

a. 处理字段名

b. 一致处理所有类型

c. 一致处理null

d. 可输出数组或多维数组

e. 对对象以及集合的细节程度可控制

f. 处理类继承结构

可编写如下代码使用该类:

public class Person {

String name;

int age;

boolean smoker;

...

public String toString() {

return new ToStringBuilder(this).

append("name", name).

append("age", age).

append("smoker", smoker).

toString();

}

}

此代码可产生字符串如下

[email protected][name=Stephen,age=29,smoker=false]

使用appendSuper可增加父类的toString()结果。

还可使用appendToString()添加其他对象的toString()结果。

此外,还有使用反射确定字段以进行文本设置的方法。因为这些字段通常是私有的,reflectionToString方法使用AccessibleObject.setAccessible来改变字段的访问权限。在安全管理下它将会失败,除非适当的权限被正确地设置。可以肯定,它将比明确字段的文本设置要慢。

该方法典型的调用应该像如下:

public String toString() {

return ToStringBuilder.reflectionToString(this);

}

你也可以使用builder来调试第三方对象:

System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));

toString的具体格式由ToStringStyle在构造方法中确定。

org.apache.commons.lang3.builder.ReflectionToStringBuilder

当使用反射重写Object.toString()方法时,可用该类进行辅助实现。

该类使用反射来确定要打印的字段。由于实体字段通常为pricate权限,该类使用AccessibleObject.setAccessible()改变字段的访问权限。在安全管理下它将会失败,除非适当的权限被正确地设置。

使用反射来访问(私有)字段可在回避同步保护机制的情况下访问这些字段。如果toString方法不能安全地读取字段,你排除调用其来辅助该类toString操作,或使用其同步机制利用其类的锁来管理整个请求过程。需要格外小心地排除线程不安全的集合类,因为这些类在修改字段时可能抛出ConcurrentModificationException。

该方法典型的调用应该像如下:

public String toString() {

return ReflectionToStringBuilder.toString(this);

}

你也可以使用builder来调试第三方对象:

System.out.println(“An object:“ + ReflectionToStringBuilder.toString(anObject));

子类可通过重写以下方法来控制字段的输出:

accept(java.lang.reflect.Field)

getValue(java.lang.reflect.Field)

例如,该方法的返回字符串则不包括password字段:

public String toString() {

return (new ReflectionToStringBuilder(this) {

protected boolean accept(Field f) {

return super.accept(f) == !f.getName().equals(“password”);

}

}).toString();

}

toString的具体格式由ToStringStyle在构造方法中确定。

在处理过程中,可以设置父类边界,然后会循环读取父类的字段,直至边界为止。取出字段后会修改访问权限,然后获取字段值进行toString()处理。

Compare部分:

org.apache.commons.lang3.builder.CompareToBuilder

当实现Comparable.compareTo()方法时,可用该类进行辅助实现。

该类与EqualsBuilder以及HashCodeBuilder构建equals()以及hashcode()是协同一致的。

两个对象如果使用compareTo()是相等的,则使用equals()应该也是相等的。

所有相关的字段都应该包括在比较的算法当中。排除的字段将被忽略。同一个字段,在同一个顺序下,应该使用相同的compareTo()以及equals()方法。

可像如下使用该方法:

public class MyClass {

String field1;

int field2;

boolean field3;

...

public int compareTo(Object o) {

MyClass myClass = (MyClass) o;

return new CompareToBuilder()

.appendSuper(super.compareTo(o)

.append(this.field1, myClass.field1)

.append(this.field2, myClass.field2)

.append(this.field3, myClass.field3)

.toComparison();

}

}

此外,还有使用reflectionCompare()方法,反射确定字段以进行字段添加的方法。因为这些字段通常是私有的,reflectionCompare方法使用AccessibleObject.setAccessible来绕过访问权限控制的检查。在安全管理下它将会失败,除非适当的权限被正确地设置。可以肯定,它将比明确字段的比较慢。

该方法典型的调用应该像如下:

public int compareTo(Object o) {

return CompareToBuilder.reflectionCompare(this, o);

}

在处理过程中,可以设置父类边界,然后会循环读取父类的字段,直至边界为止,该部分由reflectionCompare()处理。取出字段后会修改访问权限,然后获取字段值进行比较处理,该部分由最底层的reflectionAppend()完成。

Equals部分:

相等根据Object类中的表示,两个类只有hashcode相等时,equals才相等,反之亦然。因此我们将Equals以及HashCode放在一部分来说。

org.apache.commons.lang3.builder.IDKey

封装了System.identityHashCode(),因此可直接使用该类进行equals()判断。该类还消除了偶尔出现的重复哈希码问题,比较更准确。

org.apache.commons.lang3.builder.HashCodeBuilder

当实现Comparable.hashCode()方法时,可用该类进行辅助实现。

该类能为任何类创建一个良好的hashCode方法。该类遵循Joshua Bloch所作的《Effective
Java》中记录的规则。编写一个好的hashCode方法实际上是相当困难的。该类期望可以便捷地处理好。

以下是所采用的方法。当添加一个字段时,总结果将乘以乘数以得出新的总结果,然后一个新的值被用于计算。例如,如果当前哈希码是17,乘数是37,然后增加整型45将创建哈希码674,因为17
* 37 + 45。

所有对象关联的字段都应该被包含在hashCode方法中。子字段将不被包含在内。一般情况下,equals方法所使用的任何字段都必须在hashCode中使用。

可像如下使用该方法:

public class Person {

String name;

int age;

boolean smoker;

...

public int hashCode() {

// you pick a hard-coded, randomly chosen, non-zero, odd number

// ideally different for each class

return new HashCodeBuilder(17, 37).

append(name).

append(age).

append(smoker).

toHashCode();

}

}

如果需要使用父类hashCode(),可以通过appendSuper方法进行使用。

此外,还有使用反射确定字段以进行字段添加的方法。因为这些字段通常是私有的,reflectionCompare方法使用AccessibleObject.setAccessible来绕过访问权限控制的检查。在安全管理下它将会失败,除非适当的权限被正确地设置。可以肯定,它将比明确字段的比较慢。

该方法典型的调用应该像如下:

public int hashCode() {

return HashCodeBuilder.reflectionHashCode(this);

}

在处理过程中,可以设置父类边界,然后会循环读取父类的字段,直至边界为止,该部分由reflectionHashCode()处理。取出字段后会修改访问权限,然后获取字段值进行比较处理,该部分由最底层的reflectionAppend()完成。

org.apache.commons.lang3.builder.EqualsBuilder

当实现Object.equals()方法时,可用该类进行辅助实现。

类遵循Joshua Bloch所作的《Effective Java》中记录的规则。特别地,比较doubles、floats、arrays比较复杂。确保equals()和hashCode()一致也是困难的。

两个对象进行比较时,如果相等则必须生成相同的哈希码,但两个对象有相同的哈希码不一定相等。

所有对象关联的字段都应该被包含在equals方法中。子字段将不被包含在内。特别地,equals方法所使用的任何字段都必须在hashCode中使用,反之亦然。

可像如下使用该方法:

public boolean equals(Object obj) {

if (obj == null) { return false; }

if (obj == this) { return true; }

if (obj.getClass() != getClass()) {

return false;

}

MyClass rhs = (MyClass) obj;

return new EqualsBuilder()

.appendSuper(super.equals(obj))

.append(field1, rhs.field1)

.append(field2, rhs.field2)

.append(field3, rhs.field3)

.isEquals();

}

此外,还有使用反射确定字段以进行字段添加的方法。因为这些字段通常是私有的,reflectionEquals方法使用AccessibleObject.setAccessible来绕过访问权限控制的检查。在安全管理下它将会失败,除非适当的权限被正确地设置。可以肯定,它将比明确字段的比较慢。

该方法典型的调用应该像如下:

public boolean equals(Object obj) {

return EqualsBuilder.reflectionEquals(this, obj);

}

其中getRegisterPair()方法只是构造一个Pair而不是从Register里面去除Pair,该方法名容易产生误解。

ONE FOR IT是一个呆萌CTO打理的资讯读物,每天只为你准备一篇IT行业新鲜资讯。互联网的前沿,一篇就够了。(ID:OFI)

时间: 2024-10-04 10:44:58

apache commons lang 3.2(一)创建者模式部分的相关文章

Apache commons lang工具类学习笔记(2)--StringUtils

StringUtils工具类具有对String具有简单而强大的处理能力,从检查空串到分割字符串,到生成格式化的字符串,使用都很方便简洁,能减少很多代码量; 详细的使用方法可以参考下面的例子或者官方的API(http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html#isAlpha(java.lang.CharSequence)) packa

org.apache.commons.lang.exception.NestableRuntimeException等缺少jar包的解决办法

最近做服务端和客户端之间的访问,出现了 org.apache.commons.lang.exception.NestableRuntimeException等状况.实在令人头大,翻到了一个很好的帖子说明了这个问题. 原文网址如下:http://blog.csdn.net/zb0567/article/details/7893063 为方便更多的人解决这个问题,现将原文贴出 Java.lang.ClassNotFoundException: org.apache.commons.lang.exce

Caused by: java.lang.NoClassDefFoundError: org/apache/commons/lang/exception/NestableRuntimeException

转载:http://www.tuicool.com/articles/Vvia6f 缺少相应jar包都会有异常,根据异常找jar包导入...... 这里我说下lang包,因为这个包我找了好半天: 我用的是: commons-lang3-3.1.jar  出现异常: java.lang.NoClassDefFoundError: org/apache/commons/lang/exception/NestableRuntimeException 可以看出是因为缺少jar包,但是很明显我已经导入了,

java.lang.ClassNotFoundException: org.apache.commons.lang.exception.NestableRuntimeException

遇到这种问题是因为jar包引入不全,完整的应该包含: commons-beanutils-1.8.3.jar commons-lang-2.5.jar ezmorph-1.0.6.jar json-lib-2.3-jdk15.jar 但是又出现如下问题: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory 导入commons-logging-1.1.1.jar 又出现如下问题: java.lang.NoC

关于出现 org.apache.commons.lang.exception.NestableRuntimeException的解决方法

最近做服务端和客户端之间的访问,出现了 org.apache.commons.lang.exception.NestableRuntimeException等状况.实在令人头大,翻到了一个很好的帖子说明了这个问题. 原文网址如下:http://blog.csdn.net/zb0567/article/details/7893063 为方便更多的人解决这个问题,现将原文贴出 Java.lang.ClassNotFoundException: org.apache.commons.lang.exce

ssh整合启动tomcat报java.lang.ClassNotFoundException: org.apache.commons.lang.xwork.StringUtils

今天搭建了一个ssh项目环境,整合后,访问项目首页,登录不进去,控制台报错,后来调试代码后,在获取数据库数据后,返回到action时,又进入了action导致死循环,其实这里是两个问题,控制台报错如下: 2015-4-27 20:57:56 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() for servlet default threw exceptionjava.lang.ClassNotFo

【Apache Commons Lang】StopWatch任务执行时间监视器

StopWath是apache commons lang包下的一个任务执行时间监视器 主要方法:     start();     //开始计时     split();     //设置split点     getSplitTime();  //获取从start 到 最后一次split的时间     reset();     //重置计时     suspend();     //暂停计时, 直到调用resume()后才恢复计时     resume();      //恢复计时     st

org.apache.commons.lang.StringUtils 中 Join 函数

转自 http://my.oschina.net/zenglingfan/blog/134872 写代码的时候,经常会碰到需要把一个List中的每个元素,按逗号分隔转成字符串的需求,以前是自己写一段比较难看的代码,先把字符串拼出来,再把最后面多余的逗号去掉:虽然功能可以实现,但总觉得最后加的那一步操作很没有必要: public static String join(List<String> list, String seperator){ if(list.isEmpty()){ return

java开发_org.apache.commons.lang.StringUtils工具类源码

package org.apache.commons.lang; 18 19 import java.util.ArrayList; 20 import java.util.Collection; 21 import java.util.Iterator; 22 import java.util.List; 23 import java.util.Locale; 24 25 import org.apache.commons.lang.text.StrBuilder; 26 27 /** 28