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

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

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 ah!RQ2hDrV  
'0qKb*  
akgvV~5  
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 +~lPf.  
"#%9dWy  
L N'})CI8m  
WO+>W+|N  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 (|y@ ftr@  
}~<9*M-P  
nqcD#HUv  
Et)j6xz/F  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 8..g\ZT  
}.<]A  
s8r[U, }(  
UX ?S#:h  
  一、常见错误1# :多次拷贝字符串 Thp!X/2O`  
7zXX& S  
M>jk"*hA|  
FJsg3D*@J  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 %w/:mH3FA  
K!!#";Eo  
p;2NO&  
emS7q|^  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: >~G _'~_f  
@Y&(1Wl  
wF['oUwHH  
G\r>3Ys  
String s = new String ("Text here"); t@BhosR-  
tW3Nry  
o{K#LP  
zids2/_*  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: <r8s= <:  
U+ief?;4F  
2wYY0=k2  
hOcVxSc.  
String temp = "Text here"; glNXamo  
String s = new String (temp); gBy7 q09r  
- I j  
t hQ)J|1  
T`Qg+Q$  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: R"JT+m  
io4/M<6<  
{F*81q\  
Q$^Kf]pD  
String s = "Text here"; fq[,9lK  
9J f.Ls  
<\5E{/7Tl  
"3uPK$  
  二、常见错误2#: 没有克隆(clone)返回的对象 pQBhheiM  
9%bqY9NFd  
OjY#xO+'  
/y5a~3  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: /m*+N9)  
Z E},x U%  
Q-$EBNz  
E&2mFg  
import java.awt.Dimension; FZJ sZeO  
/***Example class.The x and y values should never*be negative.*/ sfEy  
public class Example{ rp,PhS  
  private Dimension d = new Dimension (0, 0); .h>tef  
  public Example (){ } |(UkI?V  
!XrnD#  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ fGDjX!3-S  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ *Zk$P.]  
   if (height < 0 || width < 0) H=>;M j  
    throw new IllegalArgumentException(); `F' >NNY  
    d.height = height; !>QD42  
     d.width = width; |),3`*N  
  } pU5t,  
/m+\oZ ]d  
  public synchronized Dimension getValues(){ PQ`~qM:3st  
   // Ooops! Breaks encapsulation N:7;c}~  
   return d; dW2Lvnh!>/  
  } dIRSgJ`  
} xrC b29{  
^ )[jBUT  
H{fOAv1*  
orr6._xw  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: 8>~\R=SC  
JnZlz?}^  
VA@t8H,  
|H@1g=q  
Example ex = new Example(); *D$Hd">X  
Dimension d = ex.getValues(); *lws7R  
d.height = -5; '/H+  
d.width = -10; |a[Id  
FaE,rzn)iD  
LuUfdzH  
!&8HA   
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 xO` O$ie  
#MI4 `FZ  
IAa}F!6Q1  
!S}4b   
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 *u`[2xmuYf  
o+.LG($+U  
>$iQDVh!  
j69 2M.A  
  更好的方式是让getValues()返回拷贝: xr'gi(.o  
DAtZp%  
|dQ-l !  
VsMTzGr  
public synchronized Dimension getValues(){ ]2o?Gnn@  
return new Dimension (d.x, d.y); lQnqPQY  
} B&k"B?9mL  
/qX=rlQ/n  
dAj;g9N/h  
y72=d?]W  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 q+/7v9  
[qGj*`@C  
lZ` CFZR0  
R#i{eE*WF  
  三、常见错误3#:不必要的克隆 \z>L,U  
,"Nfo`7  
Yr9!</;T  
{E+o+2L  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: idh5neyL  
b )mU9   
\gjY h2>  
Y$ To)qo  
/*** Example class.The value should never * be negative.*/ j)neVPf%v  
public class Example{ w-M,@[G  
  private Integer i = new Integer (0); 8@Kvh|  
  public Example (){ } \9GJa"xA`  
/kKF|Hg`c  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ 'qT[,iQ  
  public synchronized void setValues (int x) throws IllegalArgumentException{ 9 EqU 2~  
   if (x < 0) ?$&iVN^UA  
    throw new IllegalArgumentException(); iO_6>&(  
    i = new Integer (x); kX)Xo`^Ys  
  } |Q)c{9sD  
l;C00ZBOc  
  public synchronized Integer getValue(){ Xitsb f=Gg  
   // We can’t clone Integers so we makea copy this way. M@b:~mI[sw  
   return new Integer (i.intValue()); J$X{4  
  } _9Zwg+oO[  
} +vh 4I  
o> i`Jq&  
bW9a_myE  
ySk'#\d  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 > R5<D'cEN  
:6r)HJ5sg  
jR CG}'  
AvS<b3EoN  
  方法getValue()应该被写为: k&h3"  
Y={_o!9  
=5jng.  
lQSKY}h  
public synchronized Integer getValue(){ )LP=IT  
// ’i’ is immutable, so it is safe to return it instead of a copy. $ 3/G)/A  
return i; Vo2{aK;  
} 3RyB 0 n  
CtO`t5  
U94Tp A6  
O!7v&$]1  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: A=S_5y  
1D/9lR,  
Y "RjMyQh  
,XJ Xw(LM  
  ?Boolean I Y='tw  
   ?Byte sD[G?X  
   ?Character Fuuy_+p@G  
   ?Class Ur/+nL{  
   ?Double  @{|vW  
   ?Float :QV-!  
   ?Integer =83FCq"  
   ?Long  ta\CZp  
   ?Short ~T_4M  
   ?String /d\#|[S  
   ?大部分的Exception的子类 Jbrjt/OG#I  
\<bar ~  
ksB-fOv*N  
a2MFZe  
 四、常见错误4# :自编代码来拷贝数组 im6Rx=}E{  
9Rg|oCP_  
cy6lsJ"?  
?pF7g$>q  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: .(7 end<  
G2A^+R0\  
5#|f:M]Bo|  
mjwh40x.o  
public class Example{ O"D0+BK79e  
  private int[] copy; >8*J ;(:W  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ A+:X  
  public void saveCopy (int[] data){ !X5~!b^*  
   copy = new int[data.length]; P'dH*}H  
   for (int i = 0; i < copy.length; ++i) Q,.[y"m9Y.  
    copy = data; dF?:&oP]  
  } !BocF<UE  
} nF8|*}w  
8 )W{&#C>  
{O4y Y=G  
g=T !fF=  
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: gW[(gf.oo  
k{?Pgf27  
 9z9EK'g  
9F&s9(=\  
void saveCopy (int[] data){ e95x,|.-_  
  try{ U0PQ[Y#\  
   copy = (int[])data.clone(); VKjDK$  
  }catch (CloneNotSupportedException e){ }52]  
   // Can’t get here. a=m7pe ^  
  } 0\N n.x%  
} TbY <(wrMZ  
ac-R q.GQY  
5V|D%t2N  
lBbUA)z6  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: Z;nbnRz  
'D B4po.   
SP,#KyWP0)  
UY)e6 Zd  
static int[] cloneArray (int[] data){ `pHlGbrW  
  try{ nMniHB'  
   return(int[])data.clone(); km)5?  
  }catch(CloneNotSupportedException e){ &rcC7v K9  
   // Can’t get here. /ynvQ1#uA  
  } HR/"Nwr  
} "o=*f/M  
E7_)P>aS5  
: " ([i"  
b?p_mQKtZ  
  这样的话,我们的saveCopy看起来就更简洁了: @213KmB.  
ww_gG5Fc$  
<0Mc\wy  
0nh;0Z  
void saveCopy (int[] data){ UJqDZIvC  
  copy = cloneArray ( data); NaR/IsN8%  
} 8op,;Z7Y  
ugZ-*e7  
FXHcy:)}G  
{Q&@vbw'  
  五、常见错误5#:拷贝错误的数据 zjzW;bo( d  
Eagl7'x  
Ux<2!vh  
tAPr4n!  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: (&=<UGY(w  
_;;'/rs j  
9WJS.\G^  
DPU%4te  
import java.awt.Dimension; i|@lUXBp  
/*** Example class. The height and width values should never * be )CYm/dk  
negative. */ )4[Yplo  
public class Example{ U_-9rkUa  
  static final public int TOTAL_VALUES = 10; M!{;:m28X!  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; O3?3XB> <  
  public Example (){ } hU:M]O0uw  
3Ishe"  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ +}XFkH~  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ Ddf7wszW  
   if (height < 0 || width < 0) [a\U8 w  
    throw new IllegalArgumentException(); vS! TnmF  
    if (d[index] == null) :V(+]<  
     d[index] = new Dimension(); 7rc6  
     d[index].height = height; 4QK~qAi  
     d[index].width = width; w3l+BUn:X  
  } P4M*vZq)  
  public synchronized Dimension[] getValues() 3$.R=MQ7  
   throws CloneNotSupportedException{ }mz6z<pJ_  
    return (Dimension[])d.clone(); ou r$Ka31  
  } k *a?Ey$  
} e~Oge  
M@G <I]\  
^yO+-A2zC  
wkO8  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: ,?OV39h  
igoXMsifT+  
Ft7{P.g  
sXD.*D  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ -QUr|:SK:  
  Dimension[] copy = (Dimension[])d.clone(); ?r~|B/ ]  
  for (int i = 0; i < copy.length; ++i){ duCso M/  
   // NOTE: Dimension isn’t cloneable. _TB,2 R  
   if (d != null) _K4Igq  
    copy = new Dimension (d.height, d.width); d)G' y  
  } JGJXV3AT  
  return copy; =F(fum;zH  
} tWs ]Zd  
tD G[}j  
h  0EpW5  
n9Mi?#xIp  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: {,Y?+F  
e|`QW|9 .  
&\3k(j  
Dr;-2$Kt/&  
public void store (int[] data) throws CloneNotSupportedException{ U"1z"PcV  
  this.data = (int[])data.clone(); c.-/e u^|  
  // OK SJYy,F],V"  
} `zr%+  
IoEIT Kd  
>dnH  
UDJ{ iZ  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: Ueq*R(9>  
6ty>0  
Jj<UtD+  
QAp+LSm  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ ?s4-2g  
  this.data = (int[][])data.clone(); // Not OK! 8"d0Su4r  
} C~16Jj:v  
public void rightStore (int[][] data){ =%p%+F@RlW  
  // OK! X[Lwx.Ly8  
  this.data = (int[][])data.clone();  mN>7vJ  
  for (int i = 0; i < data.length; ++i){ N;<.::x  
   if (data != null) d?j_L`?+  
    this.data = (int[])data.clone(); ~0mO<0~  
  } -`z`K08sT  
} Ca: jN0  
T gpf0(  
;#3l&HRKH1  
h0YIPB  
o"O=Epg  
   六、常见错误6#:检查new 操作的结果是否为null bITc9Hqc  
`$IuN *  
`m6>r9:  
ZRDY `eK  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: '=|2, H]  
=B}a +0u!  
#WBlEVx;Z  
{-(}p+;z  
Integer i = new Integer (400); ZI'MfkEZ*  
if (i == null) A]fN~PR  
throw new NullPointerException(); }gk37_}X\I  
l 8I`%bu  
gW{<:6}!*  
'cs!(z-{x  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 KO`ftz3 +  
k7rFbrL Z  
% D]vKv~<  
zTDB]z!A  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 Hzr<i4Y=w9  
-WDU~VSU  
 七、常见错误7#:用== 替代.equals ]7 qn&(]  
SZO$#  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: 8MHYk>O~{G  
H4s^&--  
=0te.io)3O  
7Ao9MF-  
int x = 4; gWt}q-@nRR  
int y = 5; 9(;5!q,Gsg  
if (x == y) & PHejG_#  
  System.out.println ("Hi"); 3F5Y#[L`  
// This ’if’ test won’t compile. RlRkw+%m  
if (x.equals (y)) I{8fTod  
  System.out.println ("Hi"); Ekb9=/  
`1|#Za~e  
*R] Ob9X  
=T73660  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 OE{{,HFa`G  
"N"$B~W*  
9"KO!w  
q^:>sfd  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 ~r<@`[-L  
x -wIgo+  
pGQP9r%  
MAhJ>qe8 p  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 k[TVu5R  
mAycfa  
^SP/&w<c  
cE{hy 7cH  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 XILB>o.^3  
_a;E>   
S6k R o^2  
~r/"w'dB  
  八、常见错误8#: 混淆原子操作和非原子操作 3AKT>Wy =  
'r&az BO  
G,tJ\xMw8  
@J`o pR  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: (IlHg^"  
.YV{wL@cB  
*&WkorByW  
#BB,6E   
public class Example{ ^?pf.E!F`  
  private int value; // More code here... 4o+SSS  
  public void set (int x){ "r!>p\.0O  
   // NOTE: No synchronized keyword nkI+"$Rz0  
   this.value = x; J1i{n7f=@  
  } pbfIO47ZC  
} f`r o {p  
4?+K:e #F  
a`c#- je  
4LG[i}u.N  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: 26SXuFJ@  
j@N z  
CSKOtqKQ)  
C`G+b{o  
public void increment (){ L]wWJL  
  // This is effectively two or three instructions: W''%{A/'  
  // 1) Read current setting of ’value’. ~ m/nV81  
  // 2) Increment that setting. }BF!!*  
  // 3) Write the new setting back. bQU{)W  
  ++this.value; |PGF g0li  
} g=Gd|  
l ga%U~  
OyI?P_0u  
`,lm:x+(0  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: YmrrZ&]q  
d=` a-R0  
968<yO]  
z7vc|Z|  
public synchronized void increment (){ 5j8aMnvs  
  ++this.value; / .wO<l=  
} AnF"+<  
Sb2hM~  
;jgk53lo  
_Y{8FN(4  
  九、常见错误9#:在catch 块中作清除工作 Hw0S/ytY  
M~rN17S  
XmZs4~\K$G  
s3(mkdXv  
  一段在catch块中作清除工作的代码如下所示: U0ZT9/4  
Yfbo=yk  
oI\ Lepl*  
,9A1p06  
OutputStream os = null; GHs,,J;  
try{ !.2tv  
  os = new OutputStream (); =3h?!$#?  
  // Do something with os here. DOaTp f  
  os.close(); C VXz>oM  
}catch (Exception e){ %bN+Y'  
  if (os != null) :d AC:h  
  os.close(); }3825  
} "[wkjNf%  
JXx[e  
5T*Uq>x0  
OLH[F  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: W u C2 LM  
8O[br@h:5  
1>c^-"#e^  
RJ\'"XQ  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 <E2n M,  
539f B,  
jv ;8Mm  
 ff;9P5X  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 `4SwdW n  
D'8xP %P  
MyZ5~jnr\  
&GfDo4$  
  3.close()可能会抛出异常。 N9dx^+\  
`{oFdvL~)  
5cUz^ >  
; b`kN;s  
  上面代码的一个更优版本为: e,?qwZK:y  
h tuYctu`  
:5'8MU  
|F}6Zv  
OutputStream os = null; o?{-K-'B$  
try{ [g/ &%n0^  
  os = new OutputStream (); 1zcaI^e#  
  // Do something with os here. $etw'c0  
}finally{ Y 9}ga4  
  if (os != null) $~ >/_<~  
   os.close(); 9#>t% IF~  
} MaS-*;BY,  
6"oG bte  
` t6|09e  
[mcER4]}  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 ;RW0Dn)Q  
T5_/*`F  
!'z"V_x~  
6M#}&Gv  
  十、常见错误10#: 增加不必要的catch 块 EXbaijHQG  
: GdLr  
9Ro7xSeD  
8C=8Wjm  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 gq7l>vT.  
;u?L>(b  
A4tb>O M  
(|2:^T+  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。 'Q dDXw5o  
^Q#g-"b  
B9: i.rQ  
0woLB#v9  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: uj~(r=%  
~]Weyb[ N  
V r7L9%/wg  
I_s*pT  
try{ 4n0Iw  I  
  // Nifty code here Krd0Gc~\|  
}catch(Exception e){ +zg3/C4 S  
  throw e; wZg~k\_lF  
}finally{ {00Qg{;K|  
  // Cleanup code here Z [YSE T  
} Kgw, ]E&7  
vn x+1T  
M\A6;dz'  
XY,!vLjL  
  不必要的catch块被删除后,上面的代码就缩短为: _[pbf ua  
Ew )1O9f  
*5KDu$'(e  
!BjJ5m  
try{ B'-n ^';  
  // Nifty code here 8\S$iGd  
}finally{ s^"*]9B"  
  // Cleanup code here zXW)v/ ZD  
} &a'mh  
j" 5 +"j  
1wy?<B.f  
T(=Z0M  
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 V` 4/oM`  
Gm[XnUR7V  
C/!7E:  
' j\~> a3\  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 bo-lT-I  
|Sv}/ P-  
=eQ'^3a  
HE:]zH  
  小结 (&1 56 5  
6(/*E=bOKV  
ID~}pEQ  
fD*jzj7o ,  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 &S=xSs:q.  
>{{0odBF  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

您目前还是游客,请 登录注册
如果您在写长篇帖子又不马上发表,建议存为草稿
认证码:
验证问题:
3+5=?,请输入中文答案:八 正确答案:八