日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

ToStringBuilder、HashCodeBuilder、EqualsBuilder、ToStringStyle、ReflectionToStringBuilder等学习...

發(fā)布時(shí)間:2023/12/9 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ToStringBuilder、HashCodeBuilder、EqualsBuilder、ToStringStyle、ReflectionToStringBuilder等学习... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

無(wú)論你在開發(fā)哪中 Java 應(yīng)用程序,都免不了要寫很多工具類/工具函數(shù)。你可知道,有很多現(xiàn)成的工具類可用,并且代碼質(zhì)量都很不錯(cuò),不用你寫,不用你調(diào)試,只要你發(fā)現(xiàn)。

????????在 Apache Jakarta Common 中, Lang 這個(gè) Java 工具包是所有 Apache Jakarta Common 項(xiàng)目中被使用最廣泛的,幾乎你所知道的名氣比較大的軟件里面都有用到它,包括 Tomcat, Weblogic, Websphere, Eclipse 等等。我們就從這個(gè)包開始介紹整個(gè) common 項(xiàng)目。

Lang 中工具類比較多,這里介紹幾個(gè)主要的:
  ClassUtils:??getShortClassName,這個(gè)函數(shù)應(yīng)該在 java.lang.Class 類中有的,我看到很多人自己寫這個(gè)函數(shù)。getAllInterfaces,convertClassNamesToClasses,isAssignable,primitivesToWrappers,isInnerClass。
  NumberUtils: 關(guān)于數(shù)字以及數(shù)字和字符串轉(zhuǎn)換的類 stringToInt,toDouble,createNumber,isAllZeros, int compare(float lhs, float rhs), isNumber(String str),double min(double[] array)。
  RandomUtils: 用于產(chǎn)生隨機(jī)數(shù)的。
  DateFormatUtils: 日期時(shí)間格式轉(zhuǎn)換,以及本地時(shí)間和 UTC 時(shí)間轉(zhuǎn)換。
  DateUtils:?日期工具類。isSameDay,truncate,round,modify。

  基于反射機(jī)制的幾個(gè)類:
  CompareToBuilder:?比較,用在算法、排序、比較的地方。reflectionCompare,append。
  EqualsBuilder:?通過反射機(jī)制比較。reflectionEquals 很多項(xiàng)目中用到。
  HashCodeBuilder:?可以通過反射生成 hash code,很多算法的地方涉及到 hash code,但是并不是每個(gè)人都知道一種 hash code 的生成方法。
  ToStringBuilder: 當(dāng)你需要重載 toString 函數(shù)而不想寫代碼把當(dāng)前類的所有成員信息列出來(lái),可以用這個(gè)函數(shù)。

一、簡(jiǎn)介與引入
???1、ToStringBuilder、HashCodeBuilder、EqualsBuilder、ToStringStyle、ReflectionToStringBuilder、CompareToBuilder等這些類都是位于commons-lang3.jar下面的,所以要使用這些類一定要導(dǎo)入commons-lang3.jar
???2、為什么要使用ToStringBuilder?
?????系統(tǒng)中一般都要打印日志的,因?yàn)樗袑?shí)體的toString()方法 都用的是簡(jiǎn)單的"+",因?yàn)槊?#34;+" 一個(gè)就會(huì) new 一個(gè) String 對(duì)象,這樣如果系統(tǒng)內(nèi)存小的話會(huì)暴內(nèi)存(前提系統(tǒng)實(shí)體比較多)。使用ToStringBuilder就可以避免暴內(nèi)存這種問題的。

二、示例學(xué)習(xí)
??1、ToStringBuilder的append方法
?????ToStringBuilder類主要用于類的格式化輸出。ToStringBuilder中append方法可以向該類添加基本類型、數(shù)組、和對(duì)象,只有添加的方法才會(huì)被toString輸出。如:
class TaxReturn {
??private String ssn;
??private int year;
??private String lastName;
??private BigDecimal taxableIncome;
??// get/set方法省略
??public TaxReturn() {
??}
?public TaxReturn(String pSsn, int pYear, String pLastName, BigDecimal pTaxableIncome) {?
????setSsn(pSsn);?
????setYear(pYear);?
????setLastName(pLastName);?
????setTaxableIncome(pTaxableIncome);?
??}?
??public String toString() {
????return?new ToStringBuilder(this).append("ssn", ssn).append("year", year).append("lastName",
????????lastName).toString();

??}

??public int hashCode() {
????return new HashCodeBuilder(3, 7).append(ssn).append(year).toHashCode();
??}

??public boolean equals(Object pObject) {
????boolean equals = false;
????if (pObject instanceof TaxReturn) {
??????TaxReturn bean = (TaxReturn) pObject;
??????equals = (new EqualsBuilder().append(ssn, bean.ssn).append(year, bean.year)).isEquals();
????}
????return equals;
??}

??public int compareTo(Object pObject) {
????return?CompareToBuilder.reflectionCompare(this, pObject);
??}

}

public class MainClass {

??public static void main(String[] pArgs) throws Exception {
?????TaxReturn return1 = new TaxReturn("012-68-3242", 1998, "O'Brien", new BigDecimal(43000.00));
?????TaxReturn return2 = new TaxReturn("012-68-3242", 1999, "O'Brien", new BigDecimal(45000.00));
?????TaxReturn return3 = new TaxReturn("012-68-3242", 1999, "O'Brien", new BigDecimal(53222.00));
?????System.out.println("ToStringBuilder: " + return1.toString());
??}
}
運(yùn)行結(jié)果如下:
???ToStringBuilder: TaxReturn@1503a3[ssn=012-68-3242,year=1998,lastName=O'Brien]


2、ToStringBuilder的reflectionToString方法

?????該方法主要是把類對(duì)應(yīng)的基本屬性和值輸出來(lái)。如:
public class MainClass {
????public static void main(String[] args) {
????????MyClass one = new MyClass("Becker", 35);
????????MyClass two = new MyClass("Becker", 35);
????????MyClass three = new MyClass("Agassi", 33);

????????System.out.println("One>>>" + one);
????????System.out.println("Two>>>" + two);
????????System.out.println("Three>>>" + three);

????????System.out.println("one equals two? " + one.equals(two));
????????System.out.println("one equals three? " + one.equals(three));

????????System.out.println("One HashCode>>> " + one.hashCode());
????????System.out.println("Two HashCode>>> " + two.hashCode());
????????System.out.println("Three HashCode>>> " + three.hashCode());
????}
}

class MyClass {
????private String name = null;
????private int age = 0;

????public MyClass(String name, int age) {
????????this.name = name;
????????this.age = age;
????}

????public boolean equals(Object obj) {
????????return?EqualsBuilder.reflectionEquals(this, obj);
????}

????public String toString() {
????????return?ToStringBuilder.reflectionToString(this,
????????????ToStringStyle.MULTI_LINE_STYLE);

????}

????public int hashCode() {
????????return?HashCodeBuilder.reflectionHashCode(this);
????}
}
運(yùn)行結(jié)果如下:

One>>>MyClass@743399[
??name=Becker
??age=35
]
Two>>>MyClass@1d8957f[
??name=Becker
??age=35
]
Three>>>MyClass@3ee284[
??name=Agassi
??age=33
]
one equals two? true
one equals three? false
One HashCode>>> 462213092
Two HashCode>>> 462213092
Three HashCode>>> -530629296

ToStringStyle參數(shù)說(shuō)明:
1.?DEFAULT_STYLE
???com.entity.Person@182f0db[name=John Doe,age=33,smoker=false]
2.?MULTI_LINE_STYLE
????com.entity.Person@182f0db[
???name=John Doe
???age=33
???smoker=false
]
3.?NO_FIELD_NAMES_STYLE
???com.entity.Person@182f0db[John Doe,33,false]
4.?SHORT_PREFIX_STYLE???(即截去了包名)
??Person[name=John Doe,age=33,smoker=false]
5.?SIMPLE_STYLE
???John Doe,33,false

兩種方法用法優(yōu)缺點(diǎn)及一個(gè)問題

研究ApacheCommon源碼, 先從一個(gè)最簡(jiǎn)單的開始,即圍繞Object類里的toString方法自動(dòng)化實(shí)現(xiàn)的一系列類.
???
??? 怎么來(lái)自動(dòng)化地實(shí)現(xiàn)toString方法, 有兩種:反射和手動(dòng)設(shè)置.這兩種方法在上一篇博客中都有體現(xiàn),這里就不再贅述了.下面列舉下其優(yōu)缺點(diǎn).

??? 用反射方法的優(yōu)點(diǎn):
??????? 1. 代碼簡(jiǎn)潔, 不需要有什么配置的.
??????? 2, 若Model屬性有變化時(shí)不必再手動(dòng)更改toString方法的實(shí)現(xiàn).

??? 缺點(diǎn):
??????? 1, 有些屬性并不想讓toString給輸入出來(lái), (可能是沒用, 也有可能是出于密碼方面考慮),但用反射時(shí)所有屬性值都給輸了出來(lái). (這個(gè)已有解決,見下面,不過雖說(shuō)解決了,但還是不如另一種方式靈活.)
??????? 2, 安全方面的考慮. 一般來(lái)說(shuō),一個(gè)java類是的屬性都是private的,這樣用反射來(lái)構(gòu)建toString方法時(shí),就得繞過private的限制. 于是 If your system is running under a restrictive SecurityManager , you may need to alter your configuration to allow Commons Lang to bypass these security restrictions.對(duì)Java安全性問題還沒有體會(huì),現(xiàn)在寫在這里,以作備案,提醒以后注意.

??? 相比于這個(gè)反射, 直接用ToStringBuilder來(lái)配置就靈活多了.

??? 下面說(shuō)下,彌補(bǔ)用反射方法不夠靈活的一個(gè)擴(kuò)展. 由于這個(gè)是我第一次見,就放在這里,作為備案.假設(shè)一個(gè)類里有名為password這樣的屬性,一般情況下,是不想讓toString輸入的, 但用反射默認(rèn)情況下是會(huì)輸出的. 這怎么辦呢?看ReflectionToStringBuilder源碼里文檔時(shí),發(fā)現(xiàn)這么一個(gè)擴(kuò)展: 通過子類,覆蓋其accept方法來(lái)加以篩選.具體如下所示:

public String toString() {
????? return (new ReflectionToStringBuilder(this) {
// 注意這里為了表達(dá)上的簡(jiǎn)潔用了匿名內(nèi)部類.
????? protected boolean accept(Field f) {
??????? return super.accept(f) && !f.getName().equals("password");
????????? }
????? }).toString();
}

這樣在toString時(shí), 就會(huì)跳過名為password的屬性.

??? 上面記錄了兩種方法的優(yōu)缺點(diǎn)和反射時(shí)的擴(kuò)展, 其實(shí)研究完這個(gè)ToStringBuilder后,有三個(gè)收獲,上面只是第一個(gè),第三個(gè)相對(duì)來(lái)說(shuō)比較大,只能放在下一篇了,這里介紹下第二個(gè)收獲.

??? 說(shuō)是收獲,其實(shí)是一個(gè)問題,不過問題往往是新收獲的開始. 問題是這樣的:?一個(gè)private的靜態(tài)內(nèi)部類,它有一個(gè)同樣是private的方法,名為readResolve(詳見ToStringStyle的內(nèi)部類 DefaultToStringStyle),那這個(gè)方法有什么用? 不用反射這個(gè)方法是不可能被調(diào)用的. 看對(duì)這個(gè)方法的描述,說(shuō)是"Ensure Singleton after serialization".看不出來(lái)是什么意思? 怎么以前一直沒見過呢?這個(gè)問題,先放在這里.

??? 兩個(gè)小收獲寫完了, 下一篇中將介紹研究ToStringBuilder帶給我的最大收獲: abstract與設(shè)計(jì)模式.

readResolve()方法與序列化

在ToStringBuilder學(xué)習(xí)(一)中提到一個(gè)問題,即 readResolve方法是干啥的? 當(dāng)時(shí)也沒多想, 只是列在那里, 今天忙里偷閑地把搜點(diǎn)材料整理下這個(gè)問題.
原來(lái)這個(gè)方法跟對(duì)象的序列化相關(guān)(這樣倒是解釋了為什么 readResolve方法是private修飾的). ??? 怎么跟對(duì)象的序列化相關(guān)了?

下面我們先簡(jiǎn)要地回顧下對(duì)象的序列化.?一般來(lái)說(shuō), 一個(gè)類實(shí)現(xiàn)了 Serializable接口, 我們就可以把它往內(nèi)存地寫再?gòu)膬?nèi)存里讀出而"組裝"成一個(gè)跟原來(lái)一模一樣的對(duì)象. 不過當(dāng)序列化遇到單例時(shí),這里邊就有了個(gè)問題:?從內(nèi)存讀出而組裝的對(duì)象破壞了單例的規(guī)則. 單例是要求一個(gè)JVM中只有一個(gè)類對(duì)象的, 而現(xiàn)在通過反序列化,一個(gè)新的對(duì)象克隆了出來(lái).
如下例所示:
public final class MySingleton implements Serializable {
???? private MySingleton() { }
???? private static final MySingleton INSTANCE = new MySingleton();
???? public static MySingleton getInstance() { return INSTANCE; }
}


當(dāng)把 MySingleton對(duì)象(通過getInstance方法獲得的那個(gè)單例對(duì)象)序列化后再?gòu)膬?nèi)存中讀出時(shí), 就有一個(gè)全新但跟原來(lái)一樣的MySingleton對(duì)象存在了.?那怎么來(lái)維護(hù)單例模式呢?這就要用到readResolve方法了. 如下所示:
public final class MySingleton implements Serializable{
??? private MySingleton() { }
??? private static final MySingleton INSTANCE = new MySingleton();
??? public static MySingleton getInstance() { return INSTANCE; }
??? private Object readResolve() throws ObjectStreamException {
?????? // instead of the object we're on,
?????? // return the class variable INSTANCE
????? return INSTANCE;
?? }
}

這樣當(dāng)JVM從內(nèi)存中反序列化地"組裝"一個(gè)新對(duì)象時(shí),就會(huì)自動(dòng)調(diào)用這個(gè) readResolve方法來(lái)返回我們指定好的對(duì)象了, 單例規(guī)則也就得到了保證.

轉(zhuǎn)載于:https://my.oschina.net/u/3213541/blog/878816

總結(jié)

以上是生活随笔為你收集整理的ToStringBuilder、HashCodeBuilder、EqualsBuilder、ToStringStyle、ReflectionToStringBuilder等学习...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。