日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
使用自動(dòng)代碼生成工具(IDE),Java工程師要注意的那些小瑕疵

我在本文中將介紹幾個(gè)錯(cuò)誤,據(jù)我的感受,我們?cè)谟肑ava開發(fā)代碼,尤其是使用集成開發(fā)環(huán)境(IDE)的工具自動(dòng)生成代碼時(shí)經(jīng)常犯這些錯(cuò)誤。

創(chuàng)新互聯(lián)公司專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、江北網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5網(wǎng)站設(shè)計(jì)、商城系統(tǒng)網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為江北等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

自動(dòng)生成代碼很棒,它讓我們少敲打好多代碼,有助于關(guān)注領(lǐng)域問題,而不是關(guān)注樣本代碼的細(xì)枝末節(jié)。然而,有時(shí)候,我們并不認(rèn)真思考IDE為我們生成的代碼,我們留下了應(yīng)該修復(fù)的小瑕疵。我在本文中將逐一介紹這些錯(cuò)誤。

公共域

IDE在默認(rèn)情況下認(rèn)為所有類都是公共類。所以,如果我們要求IntelliJ創(chuàng)建一個(gè)新的類,就會(huì)出現(xiàn)這種情況:

 
 
  1. public class MyClass { 

在我看來,類在默認(rèn)情況下會(huì)有包作用域(package scope),即:

 
 
  1. public class MyClass { 

 

這樣一來,它們?cè)谒鶎俚陌馐遣豢梢姷摹H绻硞€(gè)時(shí)候我們需要更改類的域,就要考慮原因,并且做出便利的設(shè)計(jì)決定。如果類在默認(rèn)情況下是公共類,我們就直接拿來使用,從而增加代碼的耦合性。

要避免這個(gè)問題,***的辦法就是在我們的IDE中編輯模板。比如在IntelliJ IDEA中,這個(gè)選項(xiàng)在偏好設(shè)置>編輯器> 文件和代碼模板> 模板>類中。

我們?cè)谀J(rèn)情況下使用包作用域時(shí)的***實(shí)踐之一就是,它將接口創(chuàng)建為公共接口,但是又不暴露其實(shí)現(xiàn)。這樣一來,接口的客戶根本不知道它們使用的實(shí)現(xiàn),因?yàn)樗鼈兩踔翢o法訪問它,青睞依賴項(xiàng)注入之類的實(shí)踐。

公共域這方面的另一個(gè)例子是,IntelliJ在默認(rèn)情況下將變量創(chuàng)建為公共:

 
 
  1. public static final String CONSTANT = "value"; 

大多數(shù)時(shí)候,變量只被擁有它們的那個(gè)類使用。請(qǐng)注意這個(gè),或者更改你的模板。

不可變類

這個(gè)細(xì)節(jié)與自動(dòng)生產(chǎn)的代碼沒有直接關(guān)聯(lián),但是我們?cè)?9%的時(shí)候忽視了它。通常來說,當(dāng)我們想要設(shè)計(jì)某個(gè)類是不可變類時(shí),結(jié)果就會(huì)是這樣子:

 
 
  1. public class MyImmutableClass { 
  2.  
  3.     private final int id; 
  4.     private final String name; 
  5.  
  6.     public MyImmutableClass(int id, String name) { 
  7.         this.id = id; 
  8.         this.name = name; 
  9.     } 
  10.  
  11.     public int getId() { 
  12.         return id; 
  13.     } 
  14.  
  15.     public String getName() { 
  16.         return name; 
  17.     } 

 私有字段及最終字段,沒有setter方法,沒有構(gòu)造函數(shù)初始化。OK,這很好,但是我們遺漏了什么。不妨看看如果我們這么做,會(huì)出現(xiàn)什么情況:

 
 
  1. public class MyImmutableDerivedClass extends MyImmutableClass{ 
  2.     public String address; 
  3.     public MyImmutableDerivedClass(int id,  
  4.                                    String name,  
  5.                                    String address) { 
  6.         super(id, name); 
  7.         this.address = address; 
  8.     } 
  9.     public String getAddress() { 
  10.         return address; 
  11.     } 
  12.     public void setAddress(String address) { 
  13.         this.address = address; 
  14.     } 

這第二個(gè)類的實(shí)例(繼承自MyImmutableClass)可以充當(dāng)它的代理,客戶根本不注意,即:

 
 
  1. MyImmutableClass myImmutableClass  
  2.  
  3.                 = new MyImmutableDerivedClass(1, "name", "address");  

這并不理想,因?yàn)檫@個(gè)派生類不是不可變的! 解決辦法很簡單,我們不妨讓不可變類成為最終類:

 
 
  1. public final class MyImmutableClass {  
  2.  
  3.     //...  
  4.  
  5. }  

 現(xiàn)在就不可能創(chuàng)建派生類了。

getter和setter方法

我們常常創(chuàng)建擁有所有字段的類,并且在自動(dòng)生成的代碼這股熱潮下,為所有字段添加構(gòu)造函數(shù)、getter方法和setter方法。

我們果真需要這么做嗎?

 
 
  1. public class MyClass { 
  2.  
  3.     private Collaborator1 collaborator1; 
  4.     private Collaborator2 collaborator2; 
  5.  
  6.     public MyClass(Collaborator1 collaborator1, 
  7.                    Collaborator2 collaborator2) { 
  8.         this.collaborator1 = collaborator1; 
  9.         this.collaborator2 = collaborator2; 
  10.     } 
  11.  
  12.     public Collaborator1 getCollaborator1() { 
  13.         return collaborator1; 
  14.     } 
  15.  
  16.     public void setCollaborator1(Collaborator1 collaborator1) { 
  17.         this.collaborator1 = collaborator1; 
  18.     } 
  19.  
  20.     public Collaborator2 getCollaborator2() { 
  21.         return collaborator2; 
  22.     } 
  23.  
  24.     public void setCollaborator2(Collaborator2 collaborator2) { 
  25.         this.collaborator2 = collaborator2; 
  26.     } 

一個(gè)類應(yīng)該暴露最少數(shù)量的內(nèi)部細(xì)節(jié)。所以,前面說過一個(gè)類應(yīng)該有包作用域,直到它需要是公共的,現(xiàn)在我要說除非需要,否則類不該有g(shù)etter或setter方法。如果出現(xiàn)這種情況,就要想想這是不是***決定,或者你的設(shè)計(jì)中有沒有哪里是不合適的。

equals方法

通常來說,IDE暴露一起生成equals方法和hashCode方法的選項(xiàng)。這有必要,因?yàn)槲覀兺ǔP枰@兩種方法都有一種合適的、一致的實(shí)現(xiàn)(我在此不過多的具體解釋,假設(shè)我們都知道equals和hashCode契約)。

我不是很反對(duì)IDE為hashCode生成的實(shí)現(xiàn),它們通常是***的,盡管我們可以進(jìn)一步對(duì)它們加以優(yōu)化。不過,equals實(shí)現(xiàn)方面存在一個(gè)小問題:

 
 
  1. public class MyDerivedClass extends MyClass { 
  2.     private final String address; 
  3.  
  4.     public MyDerivedClass(int id, String name, String address) { 
  5.         super(id, name); 
  6.         this.address = address; 
  7.     } 
  8.  
  9.     public String getAddress() { 
  10.         return address; 
  11.     } 
  12.  
  13.     // equals and hashCode 

 這里一切看起來沒問題,但是出現(xiàn)了嚴(yán)重的情況:這個(gè)類違反了里氏替換原則(Liskov Substitution Principle)。這個(gè)原則是SOLID原則的一部分;簡而言之,那就是“派生類可充當(dāng)基類,客戶不會(huì)注意到它?!边@個(gè)定義有點(diǎn)費(fèi)勁(這個(gè)原則需要用一整篇文章來介紹),于是我會(huì)用一個(gè)例子來這個(gè)問題,那樣我們可以明白為何我們的equals方法有問題。

不妨創(chuàng)建一個(gè)派生類:

 
 
  1. public class MyDerivedClass extends MyClass { 
  2.     private final String address; 
  3.     public MyDerivedClass(int id, String name, String address) { 
  4.         super(id, name); 
  5.         this.address = address; 
  6.     } 
  7.     public String getAddress() { 
  8.         return address; 
  9.     } 
  10.     // equals and hashCode 

 

我忽略了equals和hashCode實(shí)現(xiàn),因?yàn)樗鼈儗?duì)這個(gè)例子來說沒有必要。

 
 
  1. public static void main(String[] args) { 
  2.     MyClass object1 = new MyClass(1, "name"); 
  3.     MyDerivedClass object2 = new MyDerivedClass(1, "name", "address"); 
  4.     System.out.println(areEquals(object1, object2)); 
  5. public static boolean areEquals(MyClass object1, MyClass object2) { 
  6.     return object1.equals(object2); 

 

方法areEquals收到MyClass的兩個(gè)實(shí)例。從含有的信息來看,這兩個(gè)實(shí)例一模一樣,所以我們認(rèn)為areEquals會(huì)返回true。但實(shí)則不然,因?yàn)樽詣?dòng)生成的equals方法執(zhí)行這個(gè)操作:

 
 
  1. if (o == null || 
  2.     getClass() != o.getClass()) 
  3.         return false; 

getClass為***個(gè)對(duì)象返回MyClass,為第二個(gè)對(duì)象返回MyDerivedClass,于是我們的方法equals返回false。

我們可以討論這種情況出現(xiàn)的頻率,因?yàn)閮烧叨际遣煌惖膶?shí)例。但是,兩個(gè)字段中所有字段的值一模一樣,果真有意義嗎?實(shí)際上,areEquals的一種替代實(shí)現(xiàn)可能是這樣:

 
 
  1. public static boolean areEquals(MyClass object1, MyClass object2) { 
  2.     return object1.getId() == object2.getId() && 
  3.             object1.getName().equals(object2.getName()); 

 

在這里,結(jié)果是true。

這就是里氏替代原則的大致內(nèi)容。這個(gè)原則的影響之一就是,如果我們覆蓋方法,它就會(huì)添加某個(gè)行為,而不清除基類執(zhí)行的任何操作。顯著違反這個(gè)原則的是,覆蓋一個(gè)方法讓它是空的這種做法(我猜許多人干過這種事)。

于是,我們需要為方法equals提供一種更好的實(shí)現(xiàn)。它應(yīng)該是這樣子:

 
 
  1. @Override 
  2. public boolean equals(Object o) { 
  3.     if (this == o) 
  4.         return true; 
  5.  
  6.     if (!(o instanceof MyClass)) 
  7.         return false; 
  8.  
  9.     MyClass myClass = (MyClass) o; 
  10.  
  11.     if (id != myClass.id) 
  12.         return false; 
  13.  
  14.     if (name != null ? 
  15.             !name.equals(myClass.name) : 
  16.             myClass.name != null) 
  17.                 return false; 
  18.  
  19.     return true; 

不是使用getClass,詢問對(duì)象知道其類,我們所做的而是,如果它是類的實(shí)例(equals駐留于運(yùn)算符instanceof),要求對(duì)象由參數(shù)傳遞給equals。這個(gè)運(yùn)算符為這個(gè)類及其派生類的實(shí)例返回true?,F(xiàn)在,我們的areEquals方法終于按我們所需的方式來工作。

事實(shí)上,IntelliJ暴露了自動(dòng)生成equals這個(gè)版本的一種方法,但是我們必須認(rèn)真選擇向?qū)С绦虻倪x項(xiàng),因?yàn)樗谀J(rèn)情況下未勾選,我們必須自行勾選。它是“Accept subclasses as parameters to equals() method”:

使用自動(dòng)代碼生成工具(IDE),要注意這些生成代碼的小瑕疵對(duì)話框本身提到,實(shí)現(xiàn)在默認(rèn)情況下違反了equals契約。Instanceof實(shí)現(xiàn)似乎與一些框架不兼容。這種情況下,我們應(yīng)該改用***個(gè)版本,但是始終要小心由此帶來的后果。所以,不妨一開始就使用正確的版本,必要時(shí)再改用B計(jì)劃。


本文題目:使用自動(dòng)代碼生成工具(IDE),Java工程師要注意的那些小瑕疵
網(wǎng)頁網(wǎng)址:http://www.5511xx.com/article/dpshdde.html