社区应用 最新帖子 精华区 社区服务 会员列表 统计排行 社区论坛任务 迷你宠物
  • 3756阅读
  • 0回复

审查Java代码的十一种常见错误

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 brdmz}  
n(L\||#+  
R +WP0&d'  
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 ^Nmg07_R  
Up,vD)tG  
mL_j4=ER@  
C@bm  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 uU:CR>=AKW  
?_Q/}@`  
Hrzf'a|^  
kn>$lTHQ  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 ^",ACWF4Sk  
|jVM&R2s  
82]vkU  
k5C@>J  
  一、常见错误1# :多次拷贝字符串 ~Q>_uw}g#  
.F(i/)vaq|  
^1L>l9F  
])Qs{hs~s  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 |"9 #bU  
i}o[- S4  
]@0NO;bK>F  
:P@rkT3Qt  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: 4y5UkU9|  
)J NSZB  
Ldl 5zc  
y !!E\b=  
String s = new String ("Text here"); V`7FKL@"  
^pe{b9c  
+{L<? "  
Pw;!uag  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: TM|)Ljm  
jMN[J|us51  
,i,q!M{-  
v0ES;  
String temp = "Text here"; [w&$|h:;  
String s = new String (temp); +C(/ Lyo}  
EB_NK  
d R]Q$CJ  
o`q_wdy?  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: YcN!T"w J@  
<1.A=_ M  
0#YX=vjX7  
i6 (a@KRY  
String s = "Text here"; A6pjRxg  
Wf&W^Q  
;XDz)`c  
-M1YE  
  二、常见错误2#: 没有克隆(clone)返回的对象 Gsc\/4Wx  
3:f[gV9K  
~~6^Sh60g  
ryc& n5  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: &09U@uc$  
n9\]S7] 52  
m/@<c'i  
 ^_%kE%I  
import java.awt.Dimension; N?m0US u*  
/***Example class.The x and y values should never*be negative.*/ A?oXqb  
public class Example{ ?"KC-u|  
  private Dimension d = new Dimension (0, 0); j$7Xs"  
  public Example (){ } 5 XA=G  
q9^  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ vc]cNz:mQ  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ \^V`ds*.  
   if (height < 0 || width < 0) fI7j):h;  
    throw new IllegalArgumentException(); Z-B%'/.  
    d.height = height; B=@ jWz"  
     d.width = width; ;kJu$U  
  } 3J=Y9 }  
BnM4T~reOF  
  public synchronized Dimension getValues(){ Go&D[#  
   // Ooops! Breaks encapsulation i"j(b|?e  
   return d; 2PR^:h2  
  } 0ilCS[`b  
} 0K-*WQ*#9  
8p!*?RRme[  
& ``d  
U5]pi+r  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: t nS+5F  
_7D_72  
4TwQO$C  
cFagz* !  
Example ex = new Example(); TbehR:B5g  
Dimension d = ex.getValues(); )!Bd6-  
d.height = -5; D5an\gE  
d.width = -10; X{g%kf,D=  
gLSA!#[ h  
$y?k[Y-~  
=]>NDWqpHN  
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 =9LC<2  
f):~8_0b  
R4<lln:[  
z1!6%W_.  
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 o y<J6  
2 /y}a#s  
oR*=|B  
K$ v"Uk  
  更好的方式是让getValues()返回拷贝: vLO&Lpv  
/"ymZI!k\  
F#{gfh  
(Bo bB]~a  
public synchronized Dimension getValues(){ i%#$*  
return new Dimension (d.x, d.y); =_[Z W  
} n tP|\E  
- ~4+w  
SjdZyJa  
F.)!3YE  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 J@9}`y=K  
~^vC,]hU  
-K[782Q  
1 11D3  
  三、常见错误3#:不必要的克隆 $A}QY5`+~S  
!eJCM`cp  
,5|d3dJS  
#' hLb  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: a9~"3y  
:h:@o h_=  
(XH2Sy  
IB|]fzy  
/*** Example class.The value should never * be negative.*/ A7P`lJgv  
public class Example{ {5%/T,  
  private Integer i = new Integer (0); +^6}   
  public Example (){ } n$2RCQ  
\nqo%5XL  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ Vdn.)ir~P  
  public synchronized void setValues (int x) throws IllegalArgumentException{ +[m8c){  
   if (x < 0) XV'fW~j\  
    throw new IllegalArgumentException(); yW.COWL=)  
    i = new Integer (x); L<(VG{)Z  
  } P.sgRsL  
k:#6^!b1  
  public synchronized Integer getValue(){ l oqvi  
   // We can’t clone Integers so we makea copy this way. Gowp <9 F  
   return new Integer (i.intValue()); a-n4:QT  
  } iS@\ =CK  
} |)W!jC&k  
B(l-}|m_  
Oe1 t\  
0>!/rR7  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 S)%_weLW7  
ad!(z[F'Y  
Qrz4}0  
# X.+  
  方法getValue()应该被写为: tiLu75vj  
'Zk<l#"}  
eSl-9 ^  
3z{S}~  
public synchronized Integer getValue(){ 4x'AC%&Qi  
// ’i’ is immutable, so it is safe to return it instead of a copy. M+sj}  
return i; bO49GEUT _  
} 0zqj0   
&WZP2Q|  
MY-.t-3  
a%hGZCI  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: >Csbjf6  
^Y^"'"  
c!&Qj  
s0{ NsK>  
  ?Boolean !W1eUY  
   ?Byte GH'O! }  
   ?Character {TZE/A3D,  
   ?Class u9![6$R  
   ?Double Y~oT)wTU  
   ?Float Rq7p29w  
   ?Integer W81o"TR|pt  
   ?Long .R5/8VuHF  
   ?Short NcL =z o<  
   ?String lVeH+"M?  
   ?大部分的Exception的子类 ~SV Q;U)-  
/aUFc'5  
Z|^MGyn  
CKTrZxR"  
 四、常见错误4# :自编代码来拷贝数组 qmmv7==  
Q?;C4n4]l  
L2U x9_S  
GYgWf1$8_D  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: da*9(!OV  
lSc,AOXp  
|l90g|isJ  
Sa] mm/ G  
public class Example{ &]nd!N  
  private int[] copy; oA3d^%(c  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ Mr6E/7g%  
  public void saveCopy (int[] data){ C<he4n.  
   copy = new int[data.length]; K[ ?R[  
   for (int i = 0; i < copy.length; ++i) KC Xwn  
    copy = data; R!{7OkC  
  } f]}}yBte`  
} 'yNPhI  
J>v$2?w`w  
.]Ybp2`"U  
v#=ayWgk  
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: n0.8)=;2  
rrQ0qg  
X^in};&d  
e?)yb^7K  
void saveCopy (int[] data){  nhfwOS  
  try{ F7 uhuqA]N  
   copy = (int[])data.clone(); P`sN&Y~m  
  }catch (CloneNotSupportedException e){ gStY8Z!k  
   // Can’t get here. 1hNEkpL^a  
  } ?1m ,SK  
} /v&`!nKu  
Am7| /  
hCLk#_  
TczXHT}G  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: GUCM4jVT^  
d]k='  
zXgkcq)  
#D:RhqjK  
static int[] cloneArray (int[] data){ |!re8|JV_  
  try{ \|!gPc%s  
   return(int[])data.clone(); S 1ibw\'  
  }catch(CloneNotSupportedException e){ ,iOZ |  
   // Can’t get here. 'aPCb`^;w  
  } gY\mXM*^  
} {gIEZ{  
UQdyv(jXq  
Bi_J5 If  
9&(.x8d,a  
  这样的话,我们的saveCopy看起来就更简洁了: 3^H/LWx`{]  
,%='>A  
aa=b<Cd  
!@yQK<0  
void saveCopy (int[] data){ 4H7Oh*P\j  
  copy = cloneArray ( data); IuWX*b`v  
} 7h1"^}M&  
M;@Ex`+?i  
| W?[,|e  
i-V0Lm/  
  五、常见错误5#:拷贝错误的数据 akrCs&Kka5  
hE5G!@1F  
3dU#Ueu  
N('3oy#8  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: 0sabh`iQ^  
c V(H<"I  
]84YvpfW  
7`+UB>8  
import java.awt.Dimension; <|dj^.^  
/*** Example class. The height and width values should never * be J<-Fua^  
negative. */ WV~SL/k|   
public class Example{ HtS#_y%(  
  static final public int TOTAL_VALUES = 10; M[vCpa  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; _pW 'n=}R  
  public Example (){ } [R$liN99z;  
`NoCH[$!+  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ Q5T(nEA  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ ,m"l\jP  
   if (height < 0 || width < 0) Q}ZBr^*]1e  
    throw new IllegalArgumentException(); tQCj)Ms'X  
    if (d[index] == null) " #J}A0  
     d[index] = new Dimension(); gTyW#verh$  
     d[index].height = height; @s?oJpo  
     d[index].width = width; Y/!0Q6<[2Y  
  } zPA>af~Ej  
  public synchronized Dimension[] getValues() X~#@rg!"  
   throws CloneNotSupportedException{ @hBx, `H^  
    return (Dimension[])d.clone(); I@c0N*(  
  } 9cbB[c_.  
} @]yQJuXA&Z  
1(D1}fcul  
L7[X|zmy*x  
 MbM :3  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: DvU~%%(0^  
M`q#,Y?3^I  
mURX I'JkX  
(2 mS v  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ M!{Rq1M  
  Dimension[] copy = (Dimension[])d.clone(); MEDskvBG  
  for (int i = 0; i < copy.length; ++i){ wN$uX#W|  
   // NOTE: Dimension isn’t cloneable. p$&_fzb  
   if (d != null) ;9 R40qi  
    copy = new Dimension (d.height, d.width); %Ud.SJ 3  
  } 7=AO^:=bx  
  return copy; v UJ sFR  
} ]eORw $f  
vBV"i9n   
N7%=K9  
Es_ SCWJ  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: dVK@Fgo  
t^dakL  
BZ8h*|uT"  
R?i-"JhW  
public void store (int[] data) throws CloneNotSupportedException{ ^2P;CAjj-  
  this.data = (int[])data.clone(); 2-/YYe;C  
  // OK 47$-5k30  
} JT}dor  
:z}~U3,JE  
mk$Yoz  
7~QwlU3n<F  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: ant-\w> }  
uugzIV)  
xQcMQ{&;  
"y3dwSS  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ .XZ 71E  
  this.data = (int[][])data.clone(); // Not OK! _,Io(QS  
} Ji)a%j1V9  
public void rightStore (int[][] data){ oc,U4+T  
  // OK! NiU tH  
  this.data = (int[][])data.clone(); f^>lObvd  
  for (int i = 0; i < data.length; ++i){ cviN$oL  
   if (data != null) =[O<.'aG-  
    this.data = (int[])data.clone(); GHJQ d&G8G  
  } '3Y0D1`v  
} `"1{Sx.  
r[i~4N=  
O=9VX  
QvT-&|  
Ve')LY<  
   六、常见错误6#:检查new 操作的结果是否为null &' oacV=  
 G$cq   
[0%Gu 5_\  
D q_{O  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: e`gGzyM  
"|~B};|MFF  
y}H*p  
2e D\_IW  
Integer i = new Integer (400); Rqd%#v  
if (i == null) \?Oly171  
throw new NullPointerException(); :pV("tHE  
'AlSq:gZ  
"ZK5P&d  
3K;b~xg`nw  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 5IB:4zx^h  
f%"_U'  
P*qNRP%  
- EX3' [*'  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 vGMOXbq4&  
lCs8`bYU  
 七、常见错误7#:用== 替代.equals t+TbCe  
]FnrbQ|  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: G5eLs  
+#*z"a`  
_bV=G#qKK  
K5c7>I%k  
int x = 4; '<E8< bi  
int y = 5; U"R.!=v  
if (x == y) zR/p}Wu|!  
  System.out.println ("Hi"); U8I~co:h  
// This ’if’ test won’t compile. bz,cfc;?$  
if (x.equals (y)) :+V1682u  
  System.out.println ("Hi"); $vicHuX!  
b42pLbpe'E  
?lw[  
D8Waf  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 qYrGe  
,Vn]Ft?n  
]j#$.$q  
:?XHZ  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 #dm@%~B{.  
 $.]t1e7s  
zinl.8Uk  
l8d%hQVqT  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 u~T$F/]k>  
u2\qg;dP  
jN[6JY1  
pnw4QQ9  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 5J#g JFA  
?m7"G)  
cz~FWk  
M&T/vByTn_  
  八、常见错误8#: 混淆原子操作和非原子操作 iOXP\:mPo  
64j 4P 7  
A,[m=9V  
12DdUPOi  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: nMvIL2:3  
8GZjIW*0oq  
bh"v{V`=0  
D&d:>.~u  
public class Example{ snNg:rT L  
  private int value; // More code here... 4< >:]  
  public void set (int x){ r.5Js*VX!  
   // NOTE: No synchronized keyword &rWJg6/  
   this.value = x; fw};.M  
  } Donf9]&U  
} Ph_m'fbf  
uvM8 8#  
`B 0*/ml  
DL!s)5!M  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: LZ]pyoi  
hQx e0Pdt  
+!Ag n)  
?6]ZQ\,  
public void increment (){ |OT%,QT|  
  // This is effectively two or three instructions: ;mxT >|z  
  // 1) Read current setting of ’value’. `IQC\DSl/  
  // 2) Increment that setting. :Lzj'Ij  
  // 3) Write the new setting back. &.4a  
  ++this.value; 3AL=*qq  
} $iJ #%&D  
P[oB'  
LtIZgOd<  
Rp9iX~A`e  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: S60`'!y  
sgsMlZ3/  
<W^~Y31:0  
^Wz{su2  
public synchronized void increment (){ yYtki  
  ++this.value; EwZt/r  
} Kg6 7cmj)f  
dju{&wo~4  
FKm2slzb  
"t`e68{Ls  
  九、常见错误9#:在catch 块中作清除工作 u[qtuM?&  
<v^.FxId  
-e\kIK %  
~WLsqP5Y~a  
  一段在catch块中作清除工作的代码如下所示: U]3JCZ{]0E  
1S#bV} !  
1'B?f# s  
4"=pcHNV  
OutputStream os = null; I2Q?7p  
try{ zwHsdB=v  
  os = new OutputStream (); g8y Zc}4  
  // Do something with os here. \MPy"uC  
  os.close(); Ob+c*@KiW  
}catch (Exception e){ K_.x(Z(;4  
  if (os != null) (dZ&Af  
  os.close(); jGPs!64f)  
} nTlrG6  
/UAj]U  
^jA^~h3(W  
PxY"{-iAM  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: z [{%.kA  
a$A S?`L  
$6Psq=|  
q[g^[~WM#  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 Iqv 5lo .  
A;PV,2|X  
_JoA=< O!  
Yuck]?#0  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 7T78S&g  
^2tCDm5  
]~,'[gWb  
n$iz   
  3.close()可能会抛出异常。 ;pq4El_  
v\u+=}r l  
07&S^ X^/  
Pr'py  
  上面代码的一个更优版本为: 35et+9  
C%h_!z":  
_uacpN/<|  
@ZZ Lh=  
OutputStream os = null; sj2+|>  
try{ :-n4! z"k  
  os = new OutputStream (); u/WkqJvw#  
  // Do something with os here. nAOId90wue  
}finally{ g}7%3D  
  if (os != null) QG ia(  
   os.close(); )^AO?MW  
} >~k Y{_  
H6QQ<~_&  
)Q`<O  
n"vI>_|G  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 cA,xf@itp  
,0O!w>u_]J  
lU3wIB  
u5,<.#EVY  
  十、常见错误10#: 增加不必要的catch 块 JM0)x}] +  
$@X,J2&  
~$<@:z{*  
-i4gzak  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 R8_qZ;t:z  
qm_\#r  
7P]pk=mo  
A2 r RYzN;  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。 B _ >|Mo/  
mJHX  
]b)(=-;>  
<KCgtO  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: e5Z\v0  
=W?c1EPLCx  
;#*mB`  
7Uh}|6PU  
try{ BL7%MvDQ  
  // Nifty code here dBkB9nz  
}catch(Exception e){ $vd._j&  
  throw e; a&JAF?k  
}finally{ 0nX5 $Kn  
  // Cleanup code here %"tf`,d~3  
} gxiJ`. D=  
sz5@=  
! JN@4  
D  UeT  
  不必要的catch块被删除后,上面的代码就缩短为: o3yZCz  
Wl{Vz  
uPpP")  
6+>rf{5P7  
try{ ft5Bk'ZJ  
  // Nifty code here <qu\q \  
}finally{ UqH7ec  
  // Cleanup code here LcXrD+ 1  
} $%<gp@Gz  
H!N,PI?rn  
3!I8J:GZ:  
l[gL(p"W  
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 +KZc"0?  
X~0P+E#  
{u7E)Fdl  
p[RD[&#b  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 B{Rig5Sc  
iJcl0)|  
rW6LMkt72  
QH;aJ(>$  
  小结 jWQB~XQY  
X^?-U ne  
a&&EjI  
*i|hcDk  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 W`KkuQ4cM  
m1TPy-|1  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

您目前还是游客,请 登录注册
欢迎提供真实交流,考虑发帖者的感受
认证码:
验证问题:
10+5=?,请输入中文答案:十五