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

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

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 b:/;  
!b0'd'xe  
7''l\3mIn  
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 \o9-[V#Gm  
{g}!M^|  
oK&LYlU  
c%v[p8 %  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 GHeJpS  
IbC(/i#%`  
egboLqn  
IlsXj`!e  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 O{a<f7 W  
pfgFHNH:  
n'=-bj`  
,wE]:|`qJ  
  一、常见错误1# :多次拷贝字符串 8<M'~G%CEq  
mh]'/C_*<w  
FR9qW$B  
R%o:'-~  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 AEx I!  
S?nk9 T+  
+9G GC  
?F20\D\V  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: aO('X3?  
w\k|^  
C J S  
_x 'R8/  
String s = new String ("Text here"); pkpD1c^  
<m9hM?^q  
xy$73K6  
=8$//$  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: | 2BIAm]  
q%TWtQS  
Sj;B1&  
[hA%VF.9  
String temp = "Text here"; .MkHB0 2N  
String s = new String (temp); M3@Wb@  
Hrq1{3~  
^]w!ow41  
n"8vlNeW  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: IY6DZP  
24PEt%2  
c^vP d]Ed  
\#.,@g  
String s = "Text here"; 'HTr02riY  
<l]P <N8^  
py.lGywb_  
/%9D$\  
  二、常见错误2#: 没有克隆(clone)返回的对象 $E3- </ f  
e*p7(b-  
l T~RH0L  
r2}u\U4>  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: ^I03PIy0l  
9Z]~c^UB  
%0C<_drW  
u-PAi5&n  
import java.awt.Dimension; sm5\> L3V  
/***Example class.The x and y values should never*be negative.*/ sS;6QkI"y  
public class Example{ :+{G|goZ*  
  private Dimension d = new Dimension (0, 0); CY#|VE M  
  public Example (){ } /ylO["<Q  
1ael{b!  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ )o)<5Iqh  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ }&D~P>1  
   if (height < 0 || width < 0) h\\fb[``  
    throw new IllegalArgumentException(); OJiW@Z_\  
    d.height = height; RY'f%c  
     d.width = width; :;W[@DeO[  
  } B.CUk.  
xF: O6KL  
  public synchronized Dimension getValues(){ E^w2IIw  
   // Ooops! Breaks encapsulation ifj%!*   
   return d; y\K r@;q0w  
  }  H"czF  
} r_nB-\  
Qb<i,`SN  
v+uq  
HE58A.Q&  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: D ]Q,~Y&'  
a0I+|fR  
zWKnkIit,  
1=(jpy  
Example ex = new Example(); c*2 U'A  
Dimension d = ex.getValues(); eJA$J=^R;  
d.height = -5; MyB&mC7Es  
d.width = -10; H'k$<S  
Y,Dd} an  
I^"ou M9}Q  
/aS=vjs  
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 /ivcqVu]  
 m=D2|WA8  
yO*~)ALb+  
-4ry)isYx  
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 mM&Sq;JJ;  
{y)O ?9q  
MCOiB <L6  
I?` }h}7.  
  更好的方式是让getValues()返回拷贝: P^V,"B8t  
-n&g**\w  
e$]`  
K"u-nroHW  
public synchronized Dimension getValues(){ .4on7<-a  
return new Dimension (d.x, d.y); <=.0 P/N  
} Pyh+HD\  
\7rAQ[\#V  
MU6|>{  
X`i'U7%I  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 )!6JSMS  
<T]%Gg8  
-]""Jl^  
Zjis0a]v~k  
  三、常见错误3#:不必要的克隆 MMlryn||1  
kQ~2mU  
{!!df.h  
!5,>[^y3  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: |^fubQs;2  
ql"&E{u?  
gc(Gc vdB\  
]0v;;PfVl6  
/*** Example class.The value should never * be negative.*/ ^b|Z<oF  
public class Example{ H$'|hUwds%  
  private Integer i = new Integer (0); U\aP  
  public Example (){ } <Sds5 d  
EdGA#i3  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ x/~qyX8vo  
  public synchronized void setValues (int x) throws IllegalArgumentException{ cUW>`F( S  
   if (x < 0) _)|_KQQu  
    throw new IllegalArgumentException(); BGM5pc (ei  
    i = new Integer (x); .*XELP=BT  
  } EUBJnf:q  
CTawXHM  
  public synchronized Integer getValue(){ Q{%2Npvq  
   // We can’t clone Integers so we makea copy this way. 1 & G0;  
   return new Integer (i.intValue()); |OW/-&)  
  } }/tT=G]91  
} 337y,;  
+c)"p4m  
`=m[(CLb  
u#(& R"6  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 6cR}Mm9Hx3  
xPBSJhla  
(al.7VA;9  
$+(Df|)  
  方法getValue()应该被写为: Mdk(FG(  
bVfFhfh*  
e^v5ai  
UN ;9h9  
public synchronized Integer getValue(){ &O|!w&  
// ’i’ is immutable, so it is safe to return it instead of a copy. :`u?pc27Sm  
return i; WFWQ;U{|  
} ^gw htnI  
Y~I$goT  
GMk\ l  
_#[~?g`  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: SCwAAE9s]  
pe^hOzVv  
(EW<Ggi  
5>9KW7^L  
  ?Boolean [3$L}m  
   ?Byte HCBZ*Z-  
   ?Character R-7.q  
   ?Class $db]b  
   ?Double 1XfH,6\8i  
   ?Float {u!Q=D$3  
   ?Integer Yz<,`w5/6~  
   ?Long V+\L@mz;  
   ?Short nP]tc  
   ?String F; upb5  
   ?大部分的Exception的子类 zzlqj){F  
jbQ N<`!  
XKp$v']u  
E lf '1  
 四、常见错误4# :自编代码来拷贝数组 +IS+!K0?)  
)-qWcf?   
TcB^Sctf  
-Iq W@|N  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: mM`zA%=  
jM <=>P  
/"~ D(bw0=  
PK&3nXF%4  
public class Example{ D.7,xgH  
  private int[] copy; K)-Gv|*t  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ OGl>i  
  public void saveCopy (int[] data){ T >pz/7gb  
   copy = new int[data.length]; (I<]@7>  
   for (int i = 0; i < copy.length; ++i) f/1soGA  
    copy = data; z-9@K<`H  
  } *[ ' n8Z  
} i 4sd29v  
D8 S?xK7[  
@.rVg XE=!  
^oZz,q  
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: }Iyr u3M][  
j@w+>h  
3HtLD5%Q  
?(C(9vO  
void saveCopy (int[] data){ ioIOyj  
  try{ Drn{ucIs  
   copy = (int[])data.clone(); Kmk}Yz  
  }catch (CloneNotSupportedException e){ Z`_`^ \"  
   // Can’t get here. 8}B*a;d  
  } R,Gr{"H  
} "hE/f~\  
w)Rtt 9  
|_<'q h  
d3nx"=Cy0I  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: t=-t xnlr<  
nqp:nw  
/mdPYV  
jCJbmEfo9@  
static int[] cloneArray (int[] data){ <5 Ye')+  
  try{ os :/-A_m  
   return(int[])data.clone(); ]^f7s36  
  }catch(CloneNotSupportedException e){ 8|-j]   
   // Can’t get here. oK-T@ &-  
  } MU  }<-1  
} ywSV4ZtM  
E$u9Jbe  
Y 6NoNc]h  
UU7E+4O&  
  这样的话,我们的saveCopy看起来就更简洁了: "-y 2En  
cpIFjb>u{  
p3m!Iota  
E1 | >O  
void saveCopy (int[] data){ 5g x9W\a ?  
  copy = cloneArray ( data); 98c##NV(7|  
} knX*fp  
Ffv v8x  
S_Tv Ix/7&  
X2RM*y|  
  五、常见错误5#:拷贝错误的数据 /0S2Om h  
 <>|&%gmz  
DGs=.U-=e  
{S9't;%]  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: +%O_xqq  
P^lzl:|  
/mi9 q  
\2UtT@3|C  
import java.awt.Dimension; SxX2+|0g`g  
/*** Example class. The height and width values should never * be S.: m$s  
negative. */ U@ ;W^Mt  
public class Example{ gY\g+df-  
  static final public int TOTAL_VALUES = 10; yN'< iTh  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; `[OJ)tHE  
  public Example (){ } cWNZ +Q8Y  
]JQ+*ZYUE  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ ;)6LX-  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ T(GEFnt Y  
   if (height < 0 || width < 0) %=ZN2)7{  
    throw new IllegalArgumentException(); b]-~{' +  
    if (d[index] == null) F!>92H~3G  
     d[index] = new Dimension(); gI~4A,  
     d[index].height = height; G}2DZ=&>'  
     d[index].width = width; \n&l  
  } wgN)*dpuI  
  public synchronized Dimension[] getValues() P#8+GN+bF  
   throws CloneNotSupportedException{ aEO``W  
    return (Dimension[])d.clone(); QNN*/n  
  } n+sV $*wvS  
} ?g ~w6|U(r  
v$WH#;(\  
8\AyKw  
i)@IV]]6yL  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: YK=o[nPmK  
bOB<m4  
C >@T+xOZ  
ak SUk)}e  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ sI/]pgt2  
  Dimension[] copy = (Dimension[])d.clone(); \zdY$3z  
  for (int i = 0; i < copy.length; ++i){ _`oP*g =  
   // NOTE: Dimension isn’t cloneable. hc2AGeZr  
   if (d != null) >}uDQwX8  
    copy = new Dimension (d.height, d.width); ?k|}\l[X1  
  } D2,2Yy5 y  
  return copy; p)x*uqSd  
} +i\ +bR  
q7z;bA  
.wdWs tQ  
!nm[ZrS P  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: %',bCd{QW  
A"Prgf eT  
a?d)l nk  
4s:S_Dw  
public void store (int[] data) throws CloneNotSupportedException{ @|=JXSr!KY  
  this.data = (int[])data.clone(); O<*l"fw3  
  // OK b`9J1p.;  
} &7fwYV  
(G E)  
,m HQ  
j;BMuLTm1  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: 7U3b YU~;  
3PBGIo  
rfz\DvV d  
wU"0@^k]<  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ k2-:! IE  
  this.data = (int[][])data.clone(); // Not OK! FFG/v`NM  
} o94]:$=~  
public void rightStore (int[][] data){ Vgj&h dbd  
  // OK! , GU|3  
  this.data = (int[][])data.clone(); un&Z' .   
  for (int i = 0; i < data.length; ++i){ ( !THd  
   if (data != null) 'XbrO|%  
    this.data = (int[])data.clone(); E7CeE6U  
  } I6.!0.G  
} bV3az/U  
I7S#vIMXR.  
"3?N*,U_  
@W|N1,sp  
8Qo~zO  
   六、常见错误6#:检查new 操作的结果是否为null L@&(>  
%k"qpu  
3IlflXb  
rw|;?a0  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: h1A/:/_M6  
pBbfU2p  
>RTmfV  
2#XYR>[  
Integer i = new Integer (400); Jc3Z1Tt  
if (i == null) hoDE*>i  
throw new NullPointerException(); +H4H$H  
NDqvt$  
j "^V?e5  
2!Gb4V  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 O^2@9 w  
hoOT]Bsn  
W5f|#{&L:  
~vGX(8N  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 T'K6Q cu  
.boBo$f  
 七、常见错误7#:用== 替代.equals 6^Q/D7U;s  
rgK:ujzW!  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: `"-ln'nw  
\ y^Ho1Fj  
p$:ERI  
SKUri  
int x = 4; \-h%z%{R  
int y = 5; qs|{  
if (x == y) ^'Z?BK  
  System.out.println ("Hi"); O/N@ Gz[g%  
// This ’if’ test won’t compile. V~~4<?=A  
if (x.equals (y)) >Av[`1a2F  
  System.out.println ("Hi"); p-S&Wq  
 45qSt2  
K.R4.{mo  
f)b+>!  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 Dus [N< w  
A@?Rj  
?b,x;hIO  
}j_2K1NS{  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 KT9!R  
*Bm7>g6  
C@ns`Eh8w  
zT< P_l  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 ~Q3y3,x  
V9 J`LQ\0  
d$?sS9"8(  
*?o`90HHP[  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 L T2UY*  
FD*) @4<o  
[ e6zCN^t  
oLh 2:c  
  八、常见错误8#: 混淆原子操作和非原子操作 _[:>!ekx  
)UoF*vC(  
3$yOv "`  
~ZuFMVR  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: N+3]C9 2o  
Y48MCL  
2|re4  
n5G|OK0,  
public class Example{ %p(!7FDE2n  
  private int value; // More code here... F^/b!)4X  
  public void set (int x){  L#>^R   
   // NOTE: No synchronized keyword 4]P5k6 nV  
   this.value = x; ToXgl4:kd  
  } !VoAN5#;  
} R2` -*PZ_  
#=81`u  
]aDU*tk  
?\.DG`Zxc  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: D00v"yp%%  
K K_  
#JD:i%  
oj'a%mx  
public void increment (){ =mQdM]A)2  
  // This is effectively two or three instructions: 2Vwv#NAV k  
  // 1) Read current setting of ’value’. 1!P\x=Nn_  
  // 2) Increment that setting. 7/>#yR  
  // 3) Write the new setting back. GX\6J]x=^2  
  ++this.value; jY|fP!?[  
} m5'nqy F  
.I#ss66h  
{Y7dE?!`7  
+~{Honj[  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: vWh]1G#'p[  
&&s3>D^Ta  
9!u&8#i  
=K:)%Qh  
public synchronized void increment (){ ~ _G W  
  ++this.value; p G-9H3[f#  
} /T\'&s3D+  
.VG5 / 6zp  
rQLl[a  
02RZ>m+  
  九、常见错误9#:在catch 块中作清除工作 CUI\:a-   
K4w#}gzok  
+f"q^RIU  
6M^NZ0~J  
  一段在catch块中作清除工作的代码如下所示: _B6W:k|-7l  
W3E7y?  
h|Ah\P?o  
cqSo%a2  
OutputStream os = null; NSV;R~"  
try{ gZW(z  
  os = new OutputStream (); >gSiH#>  
  // Do something with os here. 7mT iO?/y<  
  os.close(); BufXnMh.  
}catch (Exception e){ ;RUod .x  
  if (os != null) EU,f;H  
  os.close(); r Y#^C  
} 0n)99Osq(u  
vjz 'y[D  
- xE%`X  
7mBH #Q)  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: g=)OcTd#  
E-v#G~  
AQU^7O  
N/V~>UJ0{*  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 HD~o]l=H  
L}hc|(:  
Gzw9E.Hk  
5==hyIy  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 DV!10NqUr  
@lhjO>@#I  
pW,)yo4  
7 /7,55  
  3.close()可能会抛出异常。 7]F@ g}8  
#e*jP&1S  
9%& =n  
?K!^[aO}=  
  上面代码的一个更优版本为: O]cuJp  
{Q~HMe`,  
 c_ Dg0  
,>Yl(=&  
OutputStream os = null; 4^3lG1^YY  
try{ \ 3XG8J  
  os = new OutputStream (); DOB#PI [/  
  // Do something with os here. uN*Ynf(:-  
}finally{ ;_iDiLC;  
  if (os != null) {^*K@c  
   os.close(); j0uu* )Rk  
} u5O`|I@R  
);!IGcgF  
8_=MP[(H  
VtYrU>q  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 `P *wz<  
N/x]-$fl  
Em]2K:  
#<o=W#[  
  十、常见错误10#: 增加不必要的catch 块 6 qK`X  
MG-#p8  
8k_cC$*Ng  
p6AF16*f0  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 i}=n6  
von<I  
i1JVvNMQ,  
0?Bv zfb  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。 >)*0lfxTZ  
]WvV*FL9D3  
?8-ho0f0  
(b#4Z  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: ?8!\VNC.  
&[W53Lqa  
E@/* eJ  
qq '%9  
try{ 8s9ZY4_  
  // Nifty code here 'B9q&k%<  
}catch(Exception e){ nw,XA0M3  
  throw e; P<C=9@`!  
}finally{ 1a79]-j  
  // Cleanup code here Y{I,ipU.  
} `6RR/~kP(  
B*OBXN>'P  
wO&+Bb\=  
F S!D  
  不必要的catch块被删除后,上面的代码就缩短为: T8NDS7&?  
aL^ 58My&  
.r~M7 I  
k@|Go )~  
try{ (Tv~$\=  
  // Nifty code here @bF4'M  
}finally{ ni?5h5-  
  // Cleanup code here C17$ qdV/  
} 4vJg"*?  
C+%6N@  
PrhGp _5  
_^@>I8ix  
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 ksy]t |  
5kLz8n^z@@  
tLzb*U8'1w  
E RjMe'q4  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 k"F\4M  
2#Du5d  
NCivh&HR  
dZ|x `bIgs  
  小结 V.}3d,Em%]  
YB]{gm2  
S+bpWA  
8 k )i-&R  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 +'9E4Lpx  
agd^ga3  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

您目前还是游客,请 登录注册
批量上传需要先选择文件,再选择上传
认证码:
验证问题:
3+5=?,请输入中文答案:八 正确答案:八