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

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

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 `VXZ khm  
/Zx8nx'{V  
1ys(v   
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 O4N-_Kfp/  
y7La_FPrl  
Wxs>osq  
uOFnCy 4  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 ArL-rJ{}  
V4EM5 Z\k  
9t}J|09i  
A!4VjE>  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 *;P2+cE>H3  
/.2qWQH  
9fMSAB+c%  
_ .!aBy%xf  
  一、常见错误1# :多次拷贝字符串 .<dOED{v  
/sV?JV[t  
'+6 <U[ L  
-nG wuEngP  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 itHM7d  
Ph Ttx(!  
6J"(xT  
X\mz+al>[  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: IhwN],-V  
2!idy]vy_  
Mlwdha0  
!3 ?yG  
String s = new String ("Text here"); +0dT^Jkqg  
q- H&5K  
Y-= /,   
X?R |x[  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: :t%)5:@A  
dEG ]riO  
S?2YJ l8B  
I8Kb{[?q  
String temp = "Text here"; [n!x&f8Xh  
String s = new String (temp); m\?\6W k  
=R2l3-HA=  
DU`v J2  
!h*B (,  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: *73AAA5LKa  
BtID;^D z  
0:#7M}U  
ZHcONYAr  
String s = "Text here"; `yx56  
{?y<%@  
_{mJ.1)V;  
!")WZq^`  
  二、常见错误2#: 没有克隆(clone)返回的对象 'xk1o,;  
q^%5HeV 2  
=oPng= :  
X+%u(>>  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: T(gg>_'jh  
%:%MUdl6  
e lay =%)  
9ClF<5?M  
import java.awt.Dimension; 4M7^ [G  
/***Example class.The x and y values should never*be negative.*/ 3@'lIV ?,q  
public class Example{ ^1Yo-T(R  
  private Dimension d = new Dimension (0, 0); 8lpzSJP4k  
  public Example (){ }  qJURPK  
^H-QYuz:T0  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ Qj:{p5H'  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ .X^43 q  
   if (height < 0 || width < 0) 9j2\y=<&  
    throw new IllegalArgumentException(); %pqL-G  
    d.height = height; /xJY7yF  
     d.width = width; p KnIQa[c  
  } l:x _j\  
| 4 `.#4  
  public synchronized Dimension getValues(){ <0>[c<{V<  
   // Ooops! Breaks encapsulation UFL0 K  
   return d; c<>y!^g  
  } 1MpX] j8C#  
} RRNH0-D1l  
[m %W:Ez  
@| P3  
P.!;Uf}32  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: {)@ j77P  
T*8_FR<  
 J(^ >?d'  
\"t`W:  
Example ex = new Example(); D*qzNT@`LR  
Dimension d = ex.getValues(); 7Y)s#FJ  
d.height = -5; y6\ [1nZ  
d.width = -10; {aT92-D3  
\k4M{h6  
tfsh!)u?  
K/~Y!?:J r  
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 C_C$5[~-:  
9X.gg$P  
C5cFw/',  
;*_I,|A:Xr  
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 f7S^yA[[  
tG_-;03<`4  
WVinP(#nfM  
B JU*`Tx  
  更好的方式是让getValues()返回拷贝: 9Y\F53p&j  
UUD\bWfn  
JTjzT2`A.  
8.PXTOhVL  
public synchronized Dimension getValues(){ Z5yt]-WN&  
return new Dimension (d.x, d.y); UQSX<6"  
} $,g 3*A  
n|J.)E.  
.\)--+(  
B{^`8Htrn  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 Gi;9 S  
RsR] T]4  
py}.00it  
0@:Y>qVa  
  三、常见错误3#:不必要的克隆 .HQVj'g  
38<~R  
t]gq+ c Lo  
G[y&`Qc)G  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: tnA_!$Y a  
S[ws0Y60  
*1R##9\jU7  
</8be=e7p  
/*** Example class.The value should never * be negative.*/ {V{0^T-  
public class Example{ ,o4r,.3[s  
  private Integer i = new Integer (0); gD,A9a(3  
  public Example (){ }  \\y}DNh  
SIj6.RK  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ >t2]Ssi(  
  public synchronized void setValues (int x) throws IllegalArgumentException{ {6-;P#Q0_  
   if (x < 0) |+>%o.M&i  
    throw new IllegalArgumentException(); ^u=PdBY  
    i = new Integer (x); 2LtU;}7s  
  } $,p.=j;P  
S83]O!w0  
  public synchronized Integer getValue(){ yY-FL`-  
   // We can’t clone Integers so we makea copy this way. uPM8GIvZX.  
   return new Integer (i.intValue()); W dei`u[  
  } iH($rSE  
} ~+7ad$   
+#^sy>  
|^ 2rtI  
Y'3k E  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 0G~%UYB-  
h9,wiT  
bM*Pcxv  
AM1/\R  
  方法getValue()应该被写为: }G"r3*  
6z1aG9G  
#nxER   
U` ? zC~  
public synchronized Integer getValue(){ _%AJmt}  
// ’i’ is immutable, so it is safe to return it instead of a copy. 4`?sE*P@`  
return i; ~)WfJ  
} =d:R/Z%,  
 O6M}W_  
~e,f)?  
IwZZewb-a  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: qz-#LZFTR  
azz#@f1  
5<'n  
4SX3c:>  
  ?Boolean DQL06`pX/  
   ?Byte KIXwx98  
   ?Character o06A=4I  
   ?Class 'vqj5YTj  
   ?Double i{%z  
   ?Float ?,A}E|jZ  
   ?Integer kKFuTem_3  
   ?Long D5o+ 0R  
   ?Short 9q@ z[+X  
   ?String X}n&`y{/  
   ?大部分的Exception的子类 n"K {uj))  
; 'b!7sMO~  
hfl%r9o  
b/a?\0^  
 四、常见错误4# :自编代码来拷贝数组 6E)uu; 8  
gxBl1  
B^Rw?: hN  
t?3{s\z8+  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: o O{|C&A  
M]%!n3Fb  
Bd N{[2  
[[.&,6  
public class Example{ (;Dn%kK  
  private int[] copy; $=@9 D,R  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ ;f\R$u-  
  public void saveCopy (int[] data){ !ch[I#&J-  
   copy = new int[data.length]; Vsm%h^]d  
   for (int i = 0; i < copy.length; ++i) "63zc 1  
    copy = data; sqMNon`5  
  } softfjl&l  
} '.}6]l  
s)`1Rf  
g4.'T51  
{Q#Fen ;y|  
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: IlC:dA  
32)&;  
h0Sy'] 3m  
&K}(A{  
void saveCopy (int[] data){ Nd]%ati?  
  try{ Le#E! sU  
   copy = (int[])data.clone(); vV&AG1_Mv  
  }catch (CloneNotSupportedException e){ 4cVs(`g^  
   // Can’t get here. R~x;X3  
  } x]mye  
} -x3tx7%  
"p6:ekw  
;/hH=IT  
RT_Pd\(qD  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: (c*7VO;  
0Tn|Q9R  
sg9x?Bx9  
dl3LDB  
static int[] cloneArray (int[] data){ /!&b'7y  
  try{ edImrm1f  
   return(int[])data.clone(); 99+/W*C  
  }catch(CloneNotSupportedException e){ R; Gl{  
   // Can’t get here. `|ck5DZT5L  
  } 6S+K*/w  
} oE|u;o  
X'3`Q S:!  
J*6n6  
2gC&R1 H  
  这样的话,我们的saveCopy看起来就更简洁了: R>YMGUH~w  
f@xfb ie !  
JK^B+.  
Y/eN)  
void saveCopy (int[] data){ )2<B$p  
  copy = cloneArray ( data); ]%Q]C 8[C  
} >w]k3MC  
w7*b}D@65\  
I W] 841  
~gLEhtW  
  五、常见错误5#:拷贝错误的数据 w'zO(6 `  
)2^/?jK  
8ZDqqz^C0  
wEHrer  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: 6GrMcI@hS  
#QyK?i*  
G~iYF(:&  
Z+h7 0,|  
import java.awt.Dimension; ja,L)b:  
/*** Example class. The height and width values should never * be p#8LQP~0$  
negative. */ xjn8)C  
public class Example{ zN8V~M;  
  static final public int TOTAL_VALUES = 10; AN:RY/ %Wo  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; :x*|lz[  
  public Example (){ } ]rX?n  
>-tH&X^  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ 'i h  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ 3{#pd6e5  
   if (height < 0 || width < 0) g$^qQs)^N  
    throw new IllegalArgumentException(); WNlSve)]ie  
    if (d[index] == null) lh(+X-}D  
     d[index] = new Dimension(); J^+$L"K  
     d[index].height = height; C$re$9U  
     d[index].width = width; yM#trqv5  
  } 5, "^"*@<  
  public synchronized Dimension[] getValues() -z~ V   
   throws CloneNotSupportedException{ y\f8Ird  
    return (Dimension[])d.clone();  [k&s!Qp  
  } id[>!fQ=Y  
} B+q+)O+  
YQ8x6AJ  
(!&O4C5  
XX5(/#  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: +n.j.JP"X  
4[V6so0  
l<MCmKuYp  
hb8@br  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ K&P{2Hndr  
  Dimension[] copy = (Dimension[])d.clone(); *~oDP@[S  
  for (int i = 0; i < copy.length; ++i){ !)*T  
   // NOTE: Dimension isn’t cloneable. fz?Wr: I  
   if (d != null) /wRK[i  
    copy = new Dimension (d.height, d.width); ;KZ2L~ THG  
  } kc(b;EA  
  return copy; PG~m-W+  
} {arjW3~M:  
o-i.'L)X  
g:e8i~  
K|J#/  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: Y(!)G!CMc  
UmI@":|-  
YU\t+/b  
+7vh__  
public void store (int[] data) throws CloneNotSupportedException{ zB7dCw  
  this.data = (int[])data.clone(); ={D B  
  // OK ve]95w9J  
} =<W[dV=W  
u'n%BVt   
xXh]z |  
Bma|!p{  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: 4hr+GO@o(  
g8 *|" {  
`3s-%>  
*x` l1o  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ C5z  
  this.data = (int[][])data.clone(); // Not OK! m?CjYqvf  
} $MEbePxe  
public void rightStore (int[][] data){ {]m e?I  
  // OK! _ ~$0cj<  
  this.data = (int[][])data.clone(); =ir;m  
  for (int i = 0; i < data.length; ++i){ XV9'[V  
   if (data != null) s#Y7*?Sm  
    this.data = (int[])data.clone(); CvSG!l.6f<  
  } "dU#j,B2  
} 8o5^H>  
c+M@{EbuN  
l|QFNW[i  
z+B  
G,* uj0g  
   六、常见错误6#:检查new 操作的结果是否为null K<9MK>T  
0`Qs=R`OM  
6h*bcb#C  
J3JRWy@?P  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: iQR})=Q  
jQlK-U=oi  
rG%_O$_dO  
SmEd'YD!J  
Integer i = new Integer (400); p q5H{  
if (i == null) C xN@g'  
throw new NullPointerException(); rpI7W?hh  
(I 0t*Se  
2F(\}%UT~  
_)H+..=  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 cmLu T/oV  
AhZ  
c oz}VMp  
]OUOL/J  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 0#nXxkw  
X)+sHcE~#  
 七、常见错误7#:用== 替代.equals vPq\reKe  
W@}5e-q)O  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: H;te)km}  
)bg,rESM  
Jg6[/7*m  
oRF"[G8BV  
int x = 4; iiFKt(  
int y = 5; Re ur#K  
if (x == y) kqB 00 ;  
  System.out.println ("Hi"); Q$5:P&  
// This ’if’ test won’t compile. (ZSSp1R v  
if (x.equals (y)) '0]_8Sy&  
  System.out.println ("Hi"); !|QeYGnq6  
@Oay$gP{T  
C&"2`ll  
~ ?_Z!eS  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 t$5]1dY$X  
U,(+rMeY0  
#iU/Yg!  
bW3o%srxa  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 PKG ,4v=  
@Ec9Do>  
k/Ro74f=  
/;ITnG  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 "Y0[rSz,UW  
'.<"jZ  
m$: a|'mS  
~q>ilnL"h  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 73`UTXvWU  
n-.k&B{a  
d)sl)qt}0  
;VBfzFH  
  八、常见错误8#: 混淆原子操作和非原子操作 ^ } L$[P  
5ZxBmQ  
E6)mBAE  
9R3=h5Y  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: u^p[zepW\  
S"z4jpqn3  
RO8Ynm2 <  
U.x.gZRo[  
public class Example{ V(0[QA  
  private int value; // More code here... Or|LyQU  
  public void set (int x){ xI8*sTx 6  
   // NOTE: No synchronized keyword )Me&xQTn  
   this.value = x; p}z0(lQ*~  
  } u'> CU  
} 1 j8,Zrg1  
,:,|A/U  
9] \vw  
5+Ut]AL5  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: \ed(<e>  
NQD b;5:  
n-_w0Y  
~?r6Ax-R  
public void increment (){ pn|{P<b\  
  // This is effectively two or three instructions: "de:plMofy  
  // 1) Read current setting of ’value’. HOG7||&y  
  // 2) Increment that setting. O}V2> W$  
  // 3) Write the new setting back. \O~P !`  
  ++this.value; B~rK3BS  
} G_]mNh  
p(>'4#|qy  
^j7pF.j  
ZC-N4ESr  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: F6/bq/s  
z{x -Vfd  
EK^2 2vi$  
us+adS.l&  
public synchronized void increment (){ X}Fv*  
  ++this.value; Y$^QH.h  
} q?\D9aT9  
HC+R :Dz  
10 ^=1@U  
/ [M~##%:  
  九、常见错误9#:在catch 块中作清除工作 Rz]bCiD3 B  
-9EbU7>!  
*<1m 2t>.  
UHWun I S  
  一段在catch块中作清除工作的代码如下所示: d8po`J#nb  
ZW"J]"A  
$mlcaH  
#'P&L>6 ;  
OutputStream os = null; &s5*akG  
try{ Y*f<\z(4  
  os = new OutputStream (); LTHS&3% 2  
  // Do something with os here. S;~_9i]upe  
  os.close(); I%Z &i-33y  
}catch (Exception e){ b`mEnI VIz  
  if (os != null) Pc<ZfO #  
  os.close(); P+a&R<Dj4  
} RB2u1]l  
e{=$4F  
 o~B=[  
 "(xu  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: s~CA @  
0OXd*  
wSDDejg  
E J1:N*BA  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 *KAuyJr  
rxA<\h,A  
P^UcpU,  
7w|s8B  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 #<{MtK_  
p[Es4S}N  
_"=~aMXC.)  
"$_ypgRrSR  
  3.close()可能会抛出异常。 1mqFnVkf&+  
BKk*<WMD  
$8)/4P?OL  
xS'So7:h  
  上面代码的一个更优版本为: O?_'6T  
\c)XN<HH  
 `S|gfJ  
KH-.Z0 2U  
OutputStream os = null; SWt"QqBU  
try{ iBCM?RiG  
  os = new OutputStream (); O7W}Z1G  
  // Do something with os here. RN0Rk 8AC  
}finally{ ?d 4_'y   
  if (os != null) YA jk'  
   os.close(); PNq#o%q  
}  f!<mI8H  
Kmtr.]Nj  
lU?"\m  
1EN5ZN,  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 W!g ,  
!**q20-aP  
tB[K4GNSQ  
R)v`ZF,/b  
  十、常见错误10#: 增加不必要的catch 块 8cHZBM7'  
iZ UBw  
;8!D8o(+  
+=O:z *O  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 ;iEqa"gO  
E_? M&  
<]<50  
m~v Ie c  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。  EpiagCS  
xnArYm  
x/ez=yd*l  
xucV$[f  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: 5HB4B <2  
`JC!uc  
OA8pao~H  
$8s&=OW  
try{ oq|K:<l  
  // Nifty code here -Bc.<pFqp  
}catch(Exception e){ *oF{ R^  
  throw e; V1+IqOXAIp  
}finally{ 9wYbY* j  
  // Cleanup code here =J:~AD#  
} *ULXJZ%  
E'C[+iK6,  
ixp%aRRP  
;J4_8N-  
  不必要的catch块被删除后,上面的代码就缩短为: `f (!i mN  
*]rV,\z:  
o,d:{tt  
90q*V%cS  
try{ W uQdz&s>  
  // Nifty code here *Q)+Y&qn  
}finally{ \(u P{,ML  
  // Cleanup code here + 7Z%N9  
} NIgt"o[I  
S +He  
SXhJz=h  
Uc/%4Gx   
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 F$caKWzny5  
!({[^[!  
WA<~M) rb  
aW"BN 5eM>  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 Aam2Y,B  
v>,XJ7P  
G#csN&|,  
!l}es4~.a  
  小结 @E}4LTB  
se?nx7~  
p4/D%*G^`  
;2U`?"  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 2JbCYCTC  
ej0q*TH.  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

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