黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

java解惑你知多少(七)

系統(tǒng) 2229 0

應用

47.?不可變的引用類型

Java代碼?? 收藏代碼
  1. BigInteger?total?=?BigInteger.ZERO;??
  2. total.add( new ?BigInteger( "1" ));??
  3. total.add( new ?BigInteger( "10" ));??
  4. System.out.println(total); //0 ??

上面程序的結(jié)果為11嗎?答案是0。

?

BigInteger實例是不可變的。String、BigDecimal以及包裝類型:Integer、Long、Short、Byte、Character、Boolean、Float和Double也是如此。對這些類型的操作將返回新的實例。

?

不可變類型更容易設(shè)計、實現(xiàn)與作用;它們出錯的可能性更小,并且更加安全。

?

本程序修改如下:

Java代碼?? 收藏代碼
  1. BigInteger?total?=?BigInteger.ZERO;??
  2. total=total.add( new ?BigInteger( "1" ));??
  3. total=total.add( new ?BigInteger( "10" ));??
  4. System.out.println(total); //11 ??

?

48.?請同時重寫equals()與hashCode()

Java代碼?? 收藏代碼
  1. class ?T?{??
  2. ? private ?String?str;??
  3. ??
  4. ?T(String?str)?{??
  5. ?? this .str?=?str;??
  6. ?}??
  7. ??
  8. ? public ? boolean ?equals(Object?obj)?{??
  9. ?? if (!(obj? instanceof ?T)){??
  10. ??? return ? false ;??
  11. ??}??
  12. ??T?t?=?(T)obj;??
  13. ?? return ?t.equals( this .str);??
  14. ?}??
  15. ??
  16. ? public ? static ? void ?main(String[]?args)?{??
  17. ??Set?set?=? new ?HashSet();??
  18. ??set.add( new ?T( "str" ));??
  19. ??System.out.println(set.contains( new ?T( "str" ))); //false ??
  20. ?}??
  21. }??

上面的程序不會打印true,而是false,為什么?

?

hashCode約定要求相等的對象要具有相同的散列碼。

?

無論何時,只要你重寫了equals方法,你就必須同時重寫hashCode方法。

?

如果將自定的類型對象放入HashSet、HashMap、Hashtable、LinkedHashSet、LinkedHashMap這此散列集合時,一定需要重寫equals與hashCode方法,這樣在放入進去之后還能查找出來。如果放入其他非散列類型的集合時,其實只需要

重寫equals就可以了。

?

本程序解決辦法重寫hashCode()方法:

Java代碼?? 收藏代碼
  1. public ? int ?hashCode()?{??
  2. ? return ? 37 ?*? this .str.hashCode();??
  3. }??

?
49.?日期設(shè)置

Java代碼?? 收藏代碼
  1. Calendar?c?=?Calendar.getInstance();??
  2. c.set( 2010 ,? 12 ,? 31 ); //?月是從0開始的,11其實表示12月 ??
  3. System.out.println(c.get(Calendar.YEAR)?+? "?" ?+?c.get(Calendar.MONTH));??
  4. c?=?Calendar.getInstance();??
  5. c.set( 2010 ,? 11 ,? 31 );??
  6. System.out.println(c.get(Calendar.YEAR)?+? "?" ?+?c.get(Calendar.MONTH));??

本程序較簡單,只需注意月是從0開始的就可以了,如果你設(shè)置月為12,則會自動轉(zhuǎn)換為下一年。


50.?IdentityHashMap


?

Java代碼?? 收藏代碼
  1. class ?T?{??
  2. ? private ?String?str;??
  3. ??
  4. ?T(String?str)?{??
  5. ?? this .str?=?str;??
  6. ?}??
  7. ??
  8. ? public ? int ?hashCode()?{??
  9. ?? return ? 37 ?*? this .str.hashCode();??
  10. ?}??
  11. ??
  12. ? public ? boolean ?equals(Object?obj)?{??
  13. ?? return ? this .str.equals(((T)?obj).str);??
  14. ?}??
  15. ??
  16. ? public ? static ? void ?put(Map?m)?{??
  17. ??m.put( "str" ,? "1" );??
  18. ?? /* ?
  19. ???*?由于上面程序?qū)?"str"?放入了字符串常量池, ?
  20. ???*?所以str是同一個對象,不管是什么樣類型的 ?
  21. ???*?Map,即使使用IdentityHashMap都只放入一次 ?
  22. ???*/ ??
  23. ??m.put( "str" ,? "2" );??
  24. ??m.put( new ?T( "str" ),? "3" );??
  25. ??m.put( new ?T( "str" ),? "4" );??
  26. ?}??
  27. ??
  28. ? public ? static ? void ?main(String[]?args)?{??
  29. ??Map?m?=? new ?HashMap();??
  30. ??put(m);??
  31. ??System.out.println(m.size()); //?2 ??
  32. ?? //IdentityHashMap比較時使用==替換equals()方法 ??
  33. ??m?=? new ?IdentityHashMap();??
  34. ??put(m);??
  35. ??System.out.println(m.size()); //?3 ??
  36. ?}??
  37. }??

?

51.?靜態(tài)導入的優(yōu)先權(quán)

Java代碼?? 收藏代碼
  1. import ? static ?java.util.Arrays.toString;??
  2. import ?java.util.Arrays;??
  3. public ? class ?T?{??
  4. ? public ? static ? void ?main(String[]?args)?{??
  5. ??prt( 1 ,? 2 ,? 3 );??
  6. ?}??
  7. ? static ? void ?prt(Object...?args)?{??
  8. ?? //?自身繼承至Object類的toString的優(yōu)先級高于靜態(tài)導入的方法 ??
  9. ?? //!!?System.out.println(toString(args));//不能編譯 ??
  10. ??System.out.println(Arrays.toString(args));??
  11. ?}??
  12. }??

本身就屬于某個范圍的成員在該范圍內(nèi)與靜態(tài)導入相比具有優(yōu)先權(quán)。


52.?PrintStream對輸出結(jié)果的緩沖

Java代碼?? 收藏代碼
  1. public ? static ? void ?main(String[]?args)?{??
  2. ?String?str?=? "Hello?World" ;??
  3. ? for ?( int ?i?=? 0 ;?i?<?str.length();?i++)?{??
  4. ??System.out.write(str.charAt(i));??
  5. ?}??
  6. }??

上面的程序沒有輸出結(jié)果。

?

這里的問題在于System.out是帶有緩沖的。輸出的結(jié)果被寫入了System.out的緩沖區(qū),但是緩沖區(qū)從來都沒有被刷新。大多數(shù)人認為,當有輸出產(chǎn)生的時候System.out和System.err會自動地進制刷新,但這并不完全正確,這兩個流都屬于PrintStream類型,請看API DOC描述:一個PrintStream被創(chuàng)建為自動刷新,這意味著當一個字節(jié)數(shù)組(byte[])被寫入、或者某個println方法被調(diào)用、或者一個換行字符或字節(jié)('\n')被寫入之后,PrintStream類型的flush方法就會被自動調(diào)用。

?

令人奇怪的是,如果這個程序用print(char)去替代write(int),它就會刷新System.out并輸出結(jié)果,這種行為與print(char)的文檔是矛盾的,因為其文檔敘述道:“打印一個字符,這個字符將根據(jù)平臺缺省的字符編碼方式翻譯成一個或多個字節(jié),并且這些字節(jié)將完全按照write(int)方法的方式輸出?!?,但這里沒有換行符卻也自動的刷新了。

?

類似的,如果程序改用print(String),它也會對流進行刷新。所以調(diào)用print方法也是會自動刷新的。

?

53.?調(diào)用操作系統(tǒng)命令時被阻塞問題

Java代碼?? 收藏代碼
  1. public ? static ? void ?main(String[]?args)? throws ?IOException,??
  2. ??InterruptedException?{??
  3. ?String?command?=? "java?ProcessTest?exc" ;??
  4. ? if ?(args.length?!=? 0 )?{??
  5. ?? for ?( int ?i?=? 0 ;?i?<? 200 ;?i++)?{??
  6. ???System.out.println(command);??
  7. ???System.err.println(command);??
  8. ??}??
  9. ?}? else ?{??
  10. ??Process?process?=?Runtime.getRuntime().exec(command);????
  11. ?? int ?exitValue?=?process.waitFor();??
  12. ??System.out.println( "exit?value?=?" ?+?exitValue);??
  13. ?}??
  14. }??

執(zhí)行java ProcessTest發(fā)現(xiàn)程序阻塞。

?

Process文檔描述:由于某些本地平臺只提供有限大小的緩沖,所以如果不能迅速地讀取子進程的輸出流,就有可能會導致子進程的阻塞,甚至是死鎖。這恰好就是這里所發(fā)生的事情:沒有足夠的緩沖空間來保存這些輸出結(jié)果。為了結(jié)子進程(Process線程),父進程(Main線程)必須排空它的輸出流(標準流與錯誤流都需要排空),即要去緩存中讀取結(jié)果:

Java代碼?? 收藏代碼
  1. static ? void ?readResult( final ?InputStream?is)?{??
  2. ? new ?Thread( new ?Runnable()?{??
  3. ?? public ? void ?run()?{??
  4. ??? try ?{??
  5. ???? //?排空緩存內(nèi)容 ??
  6. ???? while ?(is.read()?>=? 0 );??
  7. ???}? catch ?(IOException?e)?{??
  8. ????e.printStackTrace();??
  9. ???}??
  10. ??}??
  11. ?}).start();??
  12. }??

?

然后在process.waitFor()之前加上

Java代碼?? 收藏代碼
  1. readResult(process.getErrorStream());??
  2. readResult(process.getInputStream());??

即可輸出exit value = 0。

?

另外,只能根據(jù)process.waitFor返回的結(jié)果來判斷操作系統(tǒng)命令執(zhí)行是否成功(成功:0,失?。?),我們不能根據(jù)

錯誤流中是否有內(nèi)容來判斷是否執(zhí)行成功。


54.?實現(xiàn)Serializable的單例問題

Java代碼?? 收藏代碼
  1. class ?Dog? implements ?Serializable{??
  2. ? public ? static ? final ?Dog?INSTANCE?=? new ?Dog();??
  3. ? private ?Dog(){}??
  4. }??

?上面能控制只生成一個單實例嗎?

?

如果對實現(xiàn)了Serializable的對象進行序列化后,再反序列化,內(nèi)中會不只一個實例了,因為反序列化時會重新生成一個對象。

?

既然INSTANCE為靜態(tài)域,那序列化時返回的對象如果也是INSTANCE就可以解決問題了,而打開API我們發(fā)現(xiàn)Serializable接口確實有這樣兩個特殊的方法描述:
??將對象寫入流時需要指定要使用的替代對象的可序列化類,應使用準確的簽名來實現(xiàn)此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此 writeReplace 方法將由序列化調(diào)用,前提是如果此方法存在,而且它可以通過被序列化對象的類中定義的一個方法訪問。因此,該方法可以擁有私有 (private)、受保護的 (protected) 和包私有 (package-private) 訪問。子類對此方法的訪問遵循 java 訪問規(guī)則。?
??在從流中讀取類的一個實例時需要指定替代的類應使用的準確簽名來實現(xiàn)此特殊方法:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此 readResolve 方法遵循與 writeReplace 相同的調(diào)用規(guī)則和訪問規(guī)則。

?

上述兩個方法的只要出現(xiàn),就會履蓋以下兩個方法(這兩個方法本質(zhì)的意義就是用來替換序列與反序列的對象),雖然會執(zhí)行它們,但最后得到的結(jié)果卻是writeReplace、readResolve兩個方法寫入或讀出的對象:
??private void writeObject(java.io.ObjectOutputStream out) throws IOException
??private void readObject(java.io.ObjectInputStream in)throws IOException, ClassNotFoundException;

?

另外,writeObject與readObject需成對實現(xiàn),而writeReplace與readResolve則不需要成對出現(xiàn),一般單獨使用。如果同時出現(xiàn)這四個方法,最后寫入與讀出的結(jié)果以writeReplace和readResolve方法的結(jié)果為準。

?

所以下要解決真真單實例問題,我們?nèi)缦滦拚?

Java代碼?? 收藏代碼
  1. class ?Dog? implements ?Serializable?{??
  2. ? public ? static ? final ?Dog?INSTANCE?=? new ?Dog();??
  3. ? private ?Dog()?{}??
  4. ? private ?Object?readResolve()?{??
  5. ?? return ?INSTANCE;??
  6. ?}??
  7. }??
  8. ??
  9. public ? class ?SerialDog?{??
  10. ? public ? static ? void ?main(String[]?args)? throws ?IOException,??
  11. ???ClassNotFoundException?{??
  12. ??ByteArrayOutputStream?bos?=? new ?ByteArrayOutputStream();??
  13. ?? new ?ObjectOutputStream(bos).writeObject(Dog.INSTANCE);??
  14. ??ByteArrayInputStream?bin?=? new ?ByteArrayInputStream(bos.toByteArray());??
  15. ??Dog?dog?=?(Dog)? new ?ObjectInputStream(bin).readObject();??
  16. ??System.out.println(dog?==?Dog.INSTANCE); //true ??
  17. ?}??
  18. }??

一個實現(xiàn)了Serializable的單例類,必須有一個readResolve方法,用以返回它的唯一實例。


55.?thread. isInterrupted()與Thread.interrupted()

Java代碼?? 收藏代碼
  1. public ? class ?SelfInerruption?{??
  2. ? public ? static ? void ?main(String[]?args)?{??
  3. ??Thread.currentThread().interrupt();??
  4. ?? if ?(Thread.interrupted())?{??
  5. ??? //?Interruped:false ??
  6. ???System.out.println( "Interruped:" ?+?Thread.interrupted());??
  7. ??}? else ?{??
  8. ???System.out.println( "Not?interruped:" ?+?Thread.interrupted());??
  9. ??}??
  10. ?}??
  11. }??

上面結(jié)果走的是第一個分支,但結(jié)果卻不是Interruped:true?

?

Thread.interrupted()為Thread的靜態(tài)方法,調(diào)用它首先會返回當前線程的中斷狀態(tài)(如果當前線程上調(diào)用了interrupt()方法,則返回true,否則為false),然后再清除當前線程的中斷狀態(tài),即將中斷狀態(tài)設(shè)置為false。換句話說,如果連續(xù)兩次調(diào)用該方法,則第二次調(diào)用將返回 false。

?

而isInterrupted()方法為實例方法,測試線程是否已經(jīng)中斷,并不會清除當前線程中斷狀態(tài)。

?

所以這里應該使用isInterrupted()實例方法,就可以修復該問題。

?

java解惑你知多少(七)


更多文章、技術(shù)交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論