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

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

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 Z |<  
qD{~QHDa  
:i* =s}cv  
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 9S8V`aC  
) h=[7}|  
V:2{LR<R8  
-GYJ)f  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 [!U! Z'i  
I.kuYD62  
b ; U  
?4#wVzuzA  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 WZcAwYB  
hZ-?-F?*@  
@# GS4I  
]4]AcJj  
  一、常见错误1# :多次拷贝字符串 EC7)M}H  
n,`j~.l-=>  
VUzRA"DP|  
!%/(a)B$^$  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 {gI%-  
#aIV\G  
b 4A1M  
_eUd RL>  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: r;GAQH}j_  
WMnxN34  
l4\!J/df  
A}_0iwG  
String s = new String ("Text here"); hpo*5Va  
+.McC$!s  
>9t+lr1   
dY`P  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: yv\ j&B|  
NGmXF_kqN  
d)L,kzN  
#BX}j&h_  
String temp = "Text here"; E6#")2C~  
String s = new String (temp); ?gG%FzfQ/  
p%IVWeZnx  
zA8Tp8(  
E=t^I/f)E  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: fr8hT(,s)  
zin'&G>l  
>Y;[+#H[  
spma\,o  
String s = "Text here"; Pa"[&{:  
\omfWWpK  
3W}qNY;J  
[uFv_G{H  
  二、常见错误2#: 没有克隆(clone)返回的对象 + De-U.  
mX G W+  
60r0O5=|Fl  
6NGQU%Hd  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: yXBWu=w3`O  
.5iXOS0 G  
kcE86Y=|x!  
6yXN7L==x  
import java.awt.Dimension; +5H1n(6)  
/***Example class.The x and y values should never*be negative.*/ YZz8xtM<2  
public class Example{ '3TfW61]  
  private Dimension d = new Dimension (0, 0); (} Y|^uM,  
  public Example (){ } p?sFX$S  
~>rn q7j  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ 9Rb tFwbn  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ V@\A<q%jTs  
   if (height < 0 || width < 0) ]wEFm;N  
    throw new IllegalArgumentException(); dl+:u}9M$  
    d.height = height; ogG:Ai)90  
     d.width = width; B0,C!??5  
  } 3<}r+,j  
8jz7t:0  
  public synchronized Dimension getValues(){ K'b #}N\  
   // Ooops! Breaks encapsulation [y(<1]i-a  
   return d; WTwura,  
  } $mn+  
} #fq&yjl#A  
iy [W:<c7j  
E<77Tj  
(4C_Ft*~j  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: 1=mb2A  
PF0AU T  
#Wely~  
dQ_yb+<  
Example ex = new Example(); OVEQ^\Q5D  
Dimension d = ex.getValues(); 7$7#z\VWu  
d.height = -5; c='uyx  
d.width = -10; sH :_sOV*  
kD#hfYs)i  
sg4TX?I   
#* Iyvx  
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 BZk0B ?  
ShJBOaE; -  
#F ;@Qi3z  
5XinZ~  
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 NH!x6p]n  
d1u6*&@lf  
imZ"4HnPP  
5wa!pR\c  
  更好的方式是让getValues()返回拷贝: zUz j F  
@^,9O92l  
T49^  
zS!+2/(  
public synchronized Dimension getValues(){ Rz=wInFs  
return new Dimension (d.x, d.y); A(ZtA[G  
} dd!Q[]$ }  
:$N{NChx  
7X/KQ97  
n*A"}i`ix  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 `tJ"wpCf6  
?d@zTAI  
H1hADn  
@P6*4W  
  三、常见错误3#:不必要的克隆 ,W5!=\Gg(  
tnFhL&  
GE |P)VO  
~0Xx]  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: 8|-064i>  
 b~Oc:  
QS2~}{v  
H?)?(t7@  
/*** Example class.The value should never * be negative.*/ 0j2M< W#  
public class Example{ &1ss @-  
  private Integer i = new Integer (0); 6|ENDd[  
  public Example (){ } - xQJY)  
G?v]|wdI  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ 07A2@dx  
  public synchronized void setValues (int x) throws IllegalArgumentException{ lZ5TDS  
   if (x < 0) CB>O%m[1  
    throw new IllegalArgumentException(); r+;AEN48  
    i = new Integer (x); za [;d4<}k  
  } cK6IyJx-  
q?Av5TFf  
  public synchronized Integer getValue(){ IC@-`S#F  
   // We can’t clone Integers so we makea copy this way.  XOd  
   return new Integer (i.intValue()); `&qeSEs\  
  } & *!) d"  
} + u'y!@VV  
!-Md+I_  
r`!S*zK  
+B-;.]L T  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 R9O[`~BA2  
ulxy 4] h  
n%}Vd `c  
h|Udw3N1L  
  方法getValue()应该被写为: j#JE4(&  
GXx/pBdy[4  
yB,{:kq7D  
"xY]&  
public synchronized Integer getValue(){ %eLf6|1x  
// ’i’ is immutable, so it is safe to return it instead of a copy. ">NPp\t>/Z  
return i; y|[YEY U)  
} DJ<F8-sb2r  
PR*qyELu  
^ G@o} Z  
`]\:%+-  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: Yeb-u+23  
Jb"0P`senY  
6o^sQ(]  
 R7-+@  
  ?Boolean 3rQ;}<*M  
   ?Byte !'T,%8']  
   ?Character k&8&D  
   ?Class {[Vkht}  
   ?Double r2;)VS  
   ?Float 8.R~Ys*  
   ?Integer >zY~")|R(  
   ?Long v^QUYsar  
   ?Short @2Ca]2,4  
   ?String +_E 96`P  
   ?大部分的Exception的子类 5/"&C-t  
A*_ |/o  
bP 8O&R  
h`:f  
 四、常见错误4# :自编代码来拷贝数组 N J_#;t#j  
*{e?%!Q  
gm}[`GMU  
&H<n76G  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: Fi!XaO  
KOM]7%ys1H  
I3$/ #  
?g\SF}2  
public class Example{ D%NVqk|  
  private int[] copy; ??tNMr5{[  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ `lA[-x~  
  public void saveCopy (int[] data){ 3om4q2R  
   copy = new int[data.length]; QN$Ac.F  
   for (int i = 0; i < copy.length; ++i) mrvPzoF,]  
    copy = data; rxVJB3P9  
  } cw)'vAE  
} )]~;A c^x  
.*>pD/  
wX!>&Gc.  
iAAlld1  
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: ;x=r.3OQy  
540,A,>:tb  
A(#4$}!n5  
'7Aj0U(  
void saveCopy (int[] data){ hy?e?^  
  try{ {F~:8 6z(g  
   copy = (int[])data.clone(); F;,LY:s|Z  
  }catch (CloneNotSupportedException e){ GE0,d  
   // Can’t get here. c6 tB9b  
  } DoYzTSWx  
} ,{_;q:  
6%&RDrn  
4H\+vJPM  
J6VG j=/  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: ?{Gf'Y}y&  
c[xH:$G?Y  
c 8 xZT  
~>( N<:N  
static int[] cloneArray (int[] data){ Ea7LPHE#  
  try{ i[wEH1jR  
   return(int[])data.clone(); z2GT9  
  }catch(CloneNotSupportedException e){  @aC2]  
   // Can’t get here. `?PpzDV7Y  
  } sb7~sa&-  
} MSMgaw?  
,Q5Z<\  
1tNmiAu  
z&@Vg`w"  
  这样的话,我们的saveCopy看起来就更简洁了: Q ]u*Oels  
z'FJx2  
6*:mc  
Td`0;R'<}c  
void saveCopy (int[] data){ n#|pR2  
  copy = cloneArray ( data); 6_w;dnVA  
} F9SkEf]99  
e{dYLQd  
BP7&w d  
6,*o;<k[  
  五、常见错误5#:拷贝错误的数据 Yc*Ex-s  
{J}Zv5  
9z:P#=Q:  
kh'R/Dt  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: \R0&*cnmo  
laQM*FLg  
;U^7 ]JO;  
9? #pqw  
import java.awt.Dimension; MMI7FlfY  
/*** Example class. The height and width values should never * be F^v <z)x  
negative. */ )$Erfu  
public class Example{ *c[X{  
  static final public int TOTAL_VALUES = 10; f_&bwfbo  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; U#jbii6e  
  public Example (){ } \*C}[D  
]y3'6!  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ jE !W&0  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ m),3J4(q  
   if (height < 0 || width < 0) Y-.pslg  
    throw new IllegalArgumentException(); L0Fhjbc  
    if (d[index] == null) `;@#yyj:_  
     d[index] = new Dimension(); <R6$ kom`  
     d[index].height = height; 6n 2LG  
     d[index].width = width; %Q}T9%Mtj  
  } ~vVsxC$.  
  public synchronized Dimension[] getValues() ~t $zypw  
   throws CloneNotSupportedException{ jH1!'1s|  
    return (Dimension[])d.clone();  {ws:g![  
  } Puu O2TZ  
} <V}^c/c!  
pMB~Lt9  
v\Y362Xv  
2VNMz[W'  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: * 7ki$f!  
#8!xIy  
fR=B/`  
BCE} Er&  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ _VeZ lk7 k  
  Dimension[] copy = (Dimension[])d.clone(); vKzq7E  
  for (int i = 0; i < copy.length; ++i){ Vp;^_,  
   // NOTE: Dimension isn’t cloneable. `dH[&=S  
   if (d != null) ;xnJ+$//U  
    copy = new Dimension (d.height, d.width); %n3lm(-0U  
  } =%4vrY `  
  return copy; >g+ogwZ  
} g,5r)FU`  
'g8~uP  
<bPn<QI  
( aGwe@AS  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: AeqxH1%  
3H0~?z_  
.[v4'ww^  
{xm^DT  
public void store (int[] data) throws CloneNotSupportedException{ z@lUaMm:F  
  this.data = (int[])data.clone(); x"@Y[  
  // OK n\Z& sc  
} NR8YVO)5$  
GW_@hYIqD  
\}0J%F1  
lNcXBtwK@#  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: o(,u"c/Or  
9rr"q5[  
&;~x{q]3  
C3Mr)  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ tL?nO#Qx  
  this.data = (int[][])data.clone(); // Not OK! Hq.ys>_  
} MLV_I4o  
public void rightStore (int[][] data){ Zh?1+Sz&  
  // OK! rrGsam\.  
  this.data = (int[][])data.clone(); FcnSO0G%  
  for (int i = 0; i < data.length; ++i){ n3, ?klK  
   if (data != null) lW! U:  
    this.data = (int[])data.clone(); FF:Y7wXW  
  } C wKo'PAJ  
} IS; F9{  
iyw "|+  
1LTl=tS#  
f n9[Li  
.6Swc?  
   六、常见错误6#:检查new 操作的结果是否为null V 0Ul`  
H\tz"<*``  
=W1`FbR  
ipB*]B F[  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: @Oe!*|?mS  
|A_yr/f  
5}3Q}o#  
r2A(GUz  
Integer i = new Integer (400); v~>^c1:  
if (i == null) &DdFK.lt  
throw new NullPointerException(); `A5^D  
)Yvf9dl  
_5I" %E;S  
SRq0y,d  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 " &B/v"nj  
PJu)%al  
Km2ppGLNn  
?pdvFM  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 CybHr#LBc  
k~WX6rEJ  
 七、常见错误7#:用== 替代.equals ,?;q$Xoi  
T"Ph@I<  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: W/U&w.$  
lgTavs  
Pb$ep|`u  
O@ jW&-;  
int x = 4; bq3G3oAyG  
int y = 5; X$w ,zb\  
if (x == y) CK1Xdyf_S  
  System.out.println ("Hi"); p(UUH3%W  
// This ’if’ test won’t compile. 2ul!f7#E  
if (x.equals (y)) b'`8$;MII  
  System.out.println ("Hi"); YK#bzu ,!  
>IO}}USm  
c#+JG  
kBd #=J  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 l+S08IZ  
AZcW f8  
8Z%C7 "4O  
u= ( kii=/  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 B3uv>\  
{'8a' 9\  
@qH{;  
'Syq!=,  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 6&7#?/Lq  
:M(%sv</  
`WHP#z  
S!o!NSn@1  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 >_h*N H  
,6?L.L  
wYZFW'5p  
 qJ!&H  
  八、常见错误8#: 混淆原子操作和非原子操作 dC;@ Fn  
n *|F=fl  
<T JUKznO  
1Iu^+  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: eZs34${fN  
!Y/$I?13Z  
[9NzvC 9I  
G (Fi  
public class Example{ 5F$ elW  
  private int value; // More code here... n\&[^Q#b|  
  public void set (int x){ "<x%kD  
   // NOTE: No synchronized keyword ]Ow A>fb  
   this.value = x; FS30RP3 `/  
  } + |MHiC  
} ZFh2v]|!  
S1NM9xHJ  
ax&,  
DE:FWD<}  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: m[,! orq  
1foy.3g-  
B/g.bh~)q  
}6MHIr=o  
public void increment (){ BXy g ?  
  // This is effectively two or three instructions: .4pWyqU)!  
  // 1) Read current setting of ’value’. @13vn x  
  // 2) Increment that setting. \wqi_[A  
  // 3) Write the new setting back. wB}s>o\  
  ++this.value; gH5E+J_$  
} 21x?TZa  
FP=%e]vJ  
VeidB!GyP  
#Q}`kFB`  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: < I[ Vv'x  
`Et)@{iP  
'Y{fah  
<z+5+h|^  
public synchronized void increment (){ ^w'y>uFM  
  ++this.value; CEjMHP$=  
} +c!v%uX  
.XQ_,  
^%tmHDNL.  
gB,~Y511  
  九、常见错误9#:在catch 块中作清除工作 o_hk!s^4m  
8TIc;'bRM  
45fk+#  
$ \0)~cy  
  一段在catch块中作清除工作的代码如下所示: }DiMt4!ZC!  
^Rriu $\  
IF-g %  
*^+8_%;1  
OutputStream os = null; V'y,{YpP  
try{ |9c J O@  
  os = new OutputStream (); ^"N]i`dIF  
  // Do something with os here. bC{1LY0  
  os.close(); 2;N)>[3*J  
}catch (Exception e){ X,dOF=OJL  
  if (os != null) ea!_/Y  
  os.close(); T@0\z1,~S  
} R+Q..9 P  
8V$pdz|[  
j t9fcw  
HAJK%zLc  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: &0A^_Z .nA  
L} r#KfIb  
<pzCpF<  
^)|8N44O  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 @}sxA9 a  
%DH2]B? 0  
ghtvAG  
(Q~ p"Ch  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 M}Sn$h_  
hfzmv~*  
Y#[jDS(ip  
"SGq$3D  
  3.close()可能会抛出异常。 "`;$wA  
RlJt+lnV  
7mG/f  
GZ xG!r -  
  上面代码的一个更优版本为: a B(_ZX'L  
tS|gQUF17  
6@ B_3y  
}.bhsy  
OutputStream os = null; $,Q0ay  
try{ Q7u/k$qN  
  os = new OutputStream (); c;X8: Z=ja  
  // Do something with os here. )?es3Ehqq  
}finally{ <0R$yB  
  if (os != null) glk-: #  
   os.close(); ,|:TML  
} %+BiN)R*x  
_Z9HOl@  
>J4Tk1//b  
S}QvG&c  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 r1vF/yt(  
s @AGU/v  
OFcL h  
=~qQ?;o n  
  十、常见错误10#: 增加不必要的catch 块 ,0j7qn@tm  
v2Lx4:dzi  
OPi><8x  
_>:R]2Ew  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 ,# i@jB  
|AgdD  
Vr%>'XN>"  
H rMH  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。 _SVIY@K|/  
h!@t8R  
"e)C.#3  
g4p-$WyT8>  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: NOzAk%s3I  
yf 7Sz$Eq  
'r/+z a:2  
h\]D:S  
try{ /RWQ+Zf-Y]  
  // Nifty code here HV*D l$  
}catch(Exception e){ 3c%dErch  
  throw e; 06)B<  
}finally{ )iKV"jsC  
  // Cleanup code here [.ya&E)x  
} QYS 1.k  
2b&&3u8  
Npr<{}ZE  
F=T};b  
  不必要的catch块被删除后,上面的代码就缩短为: D]P_tJI  
L4Nn:9b  
ftaGu-d%  
{Yt@H  
try{ cPx] :sC  
  // Nifty code here 7{"urs7 T  
}finally{ 1o Z!Up0  
  // Cleanup code here ;$il_xA)\>  
} tAi ~i;?  
f+WN=-F\  
>14 x.c  
[9-&Lq_ g  
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 zyHHz\{  
p-qt?A  
! 0}SZ  
hxT{!g  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 Kw/7X[|'G  
)XFaVkQ}  
>>>&{>}!  
Dr_ (u<[  
  小结 ntZl(]l  
GW;\ 3@o  
X5Fi , /H  
}Dc7'GZ  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 F5+)=P#  
3$~oQC  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

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