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

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

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 ],zp~yVU&  
:o:/RRp[  
I q{/-,v  
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 ZlQ&m  
9T2y2d!X  
0yb9R/3.  
,s,AkH  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 g/i.b&  
F*4G@)  
 \5HVX/  
_Qb ].~  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 BG1hk!  
btDTC 9O  
|k: FNu]C  
[E9_ZdB T  
  一、常见错误1# :多次拷贝字符串 R@IwmJxX  
k/Q8:qA  
ny<D1>{90  
&5%~Qw..  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 7e)j|a-!<  
AFsYP/g]  
_akpW  
2Fbg"de3-  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: _|COnm  
g(o^'f  
H[?l)nZ}  
0.U- tg0  
String s = new String ("Text here"); hXc:y0 0  
@A-E  
^jk-GRD*  
j:2*hF!E  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: YgQb(umK  
e,*@+E\4  
78IY&q:v&0  
tYhNr  
String temp = "Text here"; Z3dI B`@  
String s = new String (temp); }~v0o# I  
S e!B,'C%  
~yY5pnJ  
@3?dI@i(  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: oe=W}y_k  
G~f|Sx  
'pT8S  
K/!>[d  
String s = "Text here"; j Oxnf%jl  
07vzVsQ}p  
W: 3fLXk+  
$$T a  
  二、常见错误2#: 没有克隆(clone)返回的对象 /Em6+DN>  
cu4|!s`#  
1 @q"rPE^  
Tqx  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: rxeOT# N}  
_$T.N  
@:P:`Zk  
y6>fK@K~  
import java.awt.Dimension; +GNXV-S  
/***Example class.The x and y values should never*be negative.*/ 41i#w;ojI  
public class Example{ 6KX/Yj~B  
  private Dimension d = new Dimension (0, 0); X1&c?T1 %[  
  public Example (){ } |1m2h]];Q  
wkD"EuW(  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ lkQ(?7  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ W'Y#(N[ktP  
   if (height < 0 || width < 0) %p^`,b}  
    throw new IllegalArgumentException(); S|_"~Nd=  
    d.height = height; gV-A+;u  
     d.width = width; xsx0ZovhY  
  } [:l=>yJ{(  
D|/ 4),v  
  public synchronized Dimension getValues(){ 3/CKy##r%]  
   // Ooops! Breaks encapsulation ifadnl26 s  
   return d; YDGW]T]i ?  
  } x#'v}(v  
} R7Z!  
Wtp;se@#  
[9~6, ;6  
=gO4B-[  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: H) q_9<;  
3:3>k8  
=m?x5G^  
,UW!?}@  
Example ex = new Example(); 4l_~-Peh  
Dimension d = ex.getValues(); }i9VV+L#1  
d.height = -5; +3r4GEa Z  
d.width = -10; l  !JTM  
u9R@rQ9r  
uVzvUz{b  
)_1;mc8B  
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 g<Y N#  
qyR}|<F8*  
d{(NeTs  
Z \;{e'#o  
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 70N Lv  
mN1n/LNi  
Mo[yRRS#  
&LHS<Nv^:  
  更好的方式是让getValues()返回拷贝: ed$w5dv  
6rN.)dL.#N  
dg@'5.ApPu  
9QEK|x`8  
public synchronized Dimension getValues(){ *+j r? |  
return new Dimension (d.x, d.y); >4nQ&b.u  
}  x]~&4fp  
nc.:Wm6Mj  
GyQvodqD  
75H;6(7  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 WO[O0!X  
!qug^F  
6-f-/$B  
f<3lxu  
  三、常见错误3#:不必要的克隆 5a2+6N  
P$&l1Mp  
P$6 Pe>3  
PySFhb@  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: h.5KzC S  
}[SYWJIc  
\-r"%@OkW  
!>)o&sM  
/*** Example class.The value should never * be negative.*/ c2:oM<6|  
public class Example{ \qtdbi|Y  
  private Integer i = new Integer (0); =JN{j2xY  
  public Example (){ } ?$ M:4mX  
DJ|lel/'  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ 6T%5<I*&3s  
  public synchronized void setValues (int x) throws IllegalArgumentException{ pg{cZ1/  
   if (x < 0) EAK[2?CY  
    throw new IllegalArgumentException(); }gKJ~9Jg  
    i = new Integer (x); e;9x%kNs!  
  } RhkTN'vO  
8+8L'Yv;  
  public synchronized Integer getValue(){ %#E$wz  
   // We can’t clone Integers so we makea copy this way. O6Y1*XTmH6  
   return new Integer (i.intValue()); q$'[&&_  
  } Z=(Tq1t  
} @x_0AkZU  
0e(4+:0  
"b\@.7".  
e//jd&G  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 $ J!PSF8PL  
FA{(gib@9  
SZ~lCdWad  
\Yh*ywwP#  
  方法getValue()应该被写为: JV?d/[u,  
 7MQxW<0  
o,{]<Sm  
r(JP& @  
public synchronized Integer getValue(){ d2Ta&Md  
// ’i’ is immutable, so it is safe to return it instead of a copy. vK$wc~  
return i; #dQFs]:F  
} @?bY,  
g-4ab|F  
P2)/!+`a  
g1@rY0O  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: se*k56,  
ZP ]Ok  
\=Od1i  
A0bR.*3  
  ?Boolean Q+s2S>U{v  
   ?Byte u-*z#e_L0  
   ?Character S }qGf%  
   ?Class G|TnvZ KX  
   ?Double (,b\"Q  
   ?Float S" (Nf+ux  
   ?Integer g!^mewtd  
   ?Long C9*[/|T  
   ?Short Ok<,_yh  
   ?String 25<qo{  
   ?大部分的Exception的子类 ~RV"_8`V9  
J+}z*/)|#  
bmJdZD7-<k  
8+H 0  
 四、常见错误4# :自编代码来拷贝数组 Adgfo)X5  
,P=.x%  
35L\  
HubK  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: =MwR)CI#  
<r m)c.  
N?O^"  
4gZ)9ya   
public class Example{ WJMmt XO  
  private int[] copy; @^GI :z  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ J0B*V0'zR  
  public void saveCopy (int[] data){ uvJ&qd8M  
   copy = new int[data.length]; M*D@zb0ia  
   for (int i = 0; i < copy.length; ++i) uPE Ab2u="  
    copy = data; PcI~,e%  
  } 5&xbGEP$  
} N#XC%66qy!  
,aIkiT  
(LJ7xoJ^  
Z[>fFg~N4  
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: *Ea)b -  
AnK X4Q  
HE>V\+ AL  
CeM%?fr5  
void saveCopy (int[] data){ ~(B%E'  
  try{ q(A_k+NL  
   copy = (int[])data.clone(); HZ1nuA  
  }catch (CloneNotSupportedException e){ t<`d*M2w  
   // Can’t get here. "c.-`1,t  
  } ;aD?BD__Z  
} Fk9]u^j  
1 1(GCu  
&3 Ki  
ddd2w  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: Y#6LNI   
2p4iir  
lJ,\^\q  
oTx>oM,  
static int[] cloneArray (int[] data){ :))&"GY  
  try{ 2EYWX! Bx  
   return(int[])data.clone(); V]m}xZ'?^  
  }catch(CloneNotSupportedException e){ 1_l)$"  
   // Can’t get here. 7U^{xDg.b  
  } %LD(S*>7  
} m(D-?mhL  
%oWG"u  
t=|}?lN<  
1$`|$V1  
  这样的话,我们的saveCopy看起来就更简洁了: kD7'BP/#  
f2&6NC;  
~*]7f%L-  
jbUg?4k!  
void saveCopy (int[] data){ s^4wn:*$zd  
  copy = cloneArray ( data); j5A>aj  
} TBky+]p@  
uH,/S4?X  
~wOMT  
(`4&Y-  
  五、常见错误5#:拷贝错误的数据 qk>SM| {  
:RwURv+kT  
>< P<k&  
d$xvM  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: % 4t?X  
2J%L%6z8~  
dLeos9M:  
G l2WbY  
import java.awt.Dimension; 9I$} =&"  
/*** Example class. The height and width values should never * be uXvE>VpJG  
negative. */ D>ou,  
public class Example{ )s4: &!  
  static final public int TOTAL_VALUES = 10; Sa0IRC<LV  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; <|]i3_Z  
  public Example (){ } p#-=mXE/2  
eibkG  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ aBQ@n  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ 1?3+>  
   if (height < 0 || width < 0) 5w{U/v$Z  
    throw new IllegalArgumentException(); .Cs'@[Ciy  
    if (d[index] == null) jC$~m#F  
     d[index] = new Dimension(); O1\25D  
     d[index].height = height; 7y42)X  
     d[index].width = width; b'` XFB#V  
  } =<)/lz] H  
  public synchronized Dimension[] getValues() ^eefR5^_w  
   throws CloneNotSupportedException{ p! )tA  
    return (Dimension[])d.clone(); iT s" RW  
  } 2V$Jn8v,`{  
} \ bWy5/+  
2 e#"JZ=  
Z#[%JUYp'  
=|dm#w_L"  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: ;-l^X%r  
lw?C:-m  
5|t-CY{?b  
e=IbEm{|  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ *f{4 _ts  
  Dimension[] copy = (Dimension[])d.clone(); p]?eIovi  
  for (int i = 0; i < copy.length; ++i){ WE_'u+!B  
   // NOTE: Dimension isn’t cloneable. 8wZ $Hq  
   if (d != null) B# .xs>{N  
    copy = new Dimension (d.height, d.width); B<h4ZK%  
  } 4ji'6JHPg  
  return copy; 45iO2W uur  
} ,zH\P+*  
0}'/pN>  
";jAHGbO  
xG Y!r"[  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: x^Qij!mB%  
i.[k"(  
1DL+=-  
&hi][Pt  
public void store (int[] data) throws CloneNotSupportedException{ QfM^J5j.M?  
  this.data = (int[])data.clone(); f`\J%9U_O  
  // OK 3/& |Z<f  
} O8rd*+  
Ae2Y\sAV  
-x J\/"A  
J4iu8_eH!D  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: d4Y[}Fcp+  
FT}^Fi7  
>s,*=a  
4j i#Q  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ U~c9PqjZ  
  this.data = (int[][])data.clone(); // Not OK! vt5>>rl  
} ,.gJ8p(0x  
public void rightStore (int[][] data){ ;;U&mhz`  
  // OK!  P/]8+_K  
  this.data = (int[][])data.clone(); o$*DFvk  
  for (int i = 0; i < data.length; ++i){ |BGzdBm^x:  
   if (data != null) kjQI=:i=  
    this.data = (int[])data.clone(); 7Bf4ojKt  
  } cRf;7G  
} ZC^?ng  
y4!fu<[i  
~wGjr7Wt  
#SD2b,f  
wc~9zh  
   六、常见错误6#:检查new 操作的结果是否为null Th~pju  
nRX<$OzTV  
8-K4*(-dL  
Xa&:Hg<  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: O&">%aU1I  
~ r$I&8  
y92<(ziaX)  
;hFB]/.v  
Integer i = new Integer (400); U2JxzHXZ  
if (i == null) R/^;,.  
throw new NullPointerException(); 0nlh0u8#  
g|!=@9[dv  
Ac[;S!R  
#KtV4)(  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 dsb z\w3:  
wKz*)C  
MpJx>0j/J  
9AQ2FD  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 vF@.B M>  
'9|R7  
 七、常见错误7#:用== 替代.equals Z,b^f Vw  
;[Hrpl S  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: I]ol[ X0S  
Z ?w=-  
jH4Wu`r;m  
I,lzyxRP  
int x = 4; WF <*rl  
int y = 5; a.AEF P4N  
if (x == y) z7lbb*Xe  
  System.out.println ("Hi"); =iPQ\_ON@  
// This ’if’ test won’t compile. 'zTa]y]a  
if (x.equals (y)) DAd$u1  
  System.out.println ("Hi"); 0 f"M-x  
hM`*- +Zb  
H Sk}09GV  
d _koF-7  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 m^,3jssdA  
H0mDs7  
,u>K##X\  
T}A{Xu*:+H  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 &oiBMk`*  
gJBk&SDgtP  
6~q"#94  
cNqw(\rr  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 g/soop\:  
4:v{\R  
J7rfHhz  
hn u/  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 H=9\B}  
GpM_ Qp  
mdHC{sp  
}L*cP;m#  
  八、常见错误8#: 混淆原子操作和非原子操作 Cqk6Igw  
S>p>$m, Q  
-n'%MT=Cd  
b; 4;WtBO  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: meV RdQ  
;rH@>VrR  
jDc5p3D&[]  
PK* $  
public class Example{ [t`QV2um  
  private int value; // More code here... .oo>NS  
  public void set (int x){ BK]q^.7+:  
   // NOTE: No synchronized keyword 1 {V*(=Tp  
   this.value = x; Y,@{1X`0@3  
  } }KHdlhD  
} Z5o6RTi  
 `#lNur\x  
ToVm]zPOUt  
3J}bI {3  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: r 6STc,%5  
AHhck?M^  
RtR]9^:~  
FiqcM-Af4  
public void increment (){ lU.@! rGbw  
  // This is effectively two or three instructions: L[*Xrp;/&  
  // 1) Read current setting of ’value’. _`zj^*%  
  // 2) Increment that setting. OPwj*b:-m  
  // 3) Write the new setting back. y8un&LP  
  ++this.value; 3say&|kJ  
} u#Qd `@p  
d1#;>MiU  
eJ#q! <   
yg gQ4y6  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: 6nRD:CH)X  
;Z"6ve4  
ALiXT8q  
  Hs8c%C  
public synchronized void increment (){ MD S;qZx=  
  ++this.value; eUA6X ,I  
} /AP@Bhm  
N$H0o+9-Y  
o+(.Pb  
W9?Vh{w  
  九、常见错误9#:在catch 块中作清除工作 kQ~*iY  
n8[ sl]L  
[= -?n6  
nJ4i[j8  
  一段在catch块中作清除工作的代码如下所示: b$+.}&M  
jyf[O -  
&gZ5dTj>  
^'~+w3M@  
OutputStream os = null; >v`lsCGb  
try{ \&J7>vu^y  
  os = new OutputStream (); V7!x-E/  
  // Do something with os here. n97A'"'wz  
  os.close(); |?SK.1pW  
}catch (Exception e){ E[>4b7{g:  
  if (os != null) 7%9Sz5z  
  os.close(); bH&Cbme90-  
} }N1Z7G  
TDdFuO'}  
UfSWdR)  
)W~w72j-  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: _gjsAbM  
vW 0m%  
1y l2i|m+  
;-47d ^  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 EaG3:<>J  
Q d]5e  
0}k[s+^  
7$+n"Cfm  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 ?ZDXT2b~~  
Y!v `0z  
K>9]I97g'  
] FvN*@lG  
  3.close()可能会抛出异常。 q 4PRc<\^  
J_OIU#-B  
.xuLvNyQr  
/NaI Mo 5  
  上面代码的一个更优版本为: `9Zoq=/  
ZFNM>C^  
DTk)Y-eQ  
jzSh|a9_  
OutputStream os = null; snO d 3Bw  
try{ ^[Cpu_]D  
  os = new OutputStream (); [WnX'R R  
  // Do something with os here. ")"VQ|$y  
}finally{ r.0IC*Y  
  if (os != null) "]Wrir?l  
   os.close(); : I28Zi*  
} tbF>"?FY/  
-z./6dQ  
Wc ]BQn  
U0q{8 "Pl  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 EFu2&P  
W# E`h  
$]K gs6=r  
!*ct3{m  
  十、常见错误10#: 增加不必要的catch 块 YwyP+S r\  
W'u6F-$2  
%>Z^BM<e  
?*|AcMw5  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 n~l9`4wJY  
,3 &XV%1  
wv>*g:El'  
#'fh'$5"  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。 kg?[   
Q;W[$yvW  
nfET;:{  
[Hw  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: CRf!tsj@  
N7:=%Fy(  
@^]wT_r  
iz!E1(z(  
try{ . >[d:0  
  // Nifty code here q&OF?z7H  
}catch(Exception e){ Qn'Do4Le  
  throw e; ;[TC`DuNj0  
}finally{ 8}z]B^?Fy  
  // Cleanup code here {q f gvu  
} jA_w OR7$  
I.BsKB  
vaN}M)W/  
qniP`P4E  
  不必要的catch块被删除后,上面的代码就缩短为: 5SPhdpIg@[  
n "?It  
n+ 1!/H=d  
vFKX@wV S  
try{ "~-H]9  
  // Nifty code here D#Qfa!=g  
}finally{ vU,AOK[l{  
  // Cleanup code here :j_OO5b!  
} !lQGoXQ'4  
"c5C0 pK0  
aK>5r^7S  
aDEz |>q  
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 wMFo8;L  
5@l[!Jl0k  
?4>uGaU\  
|^!#x Tj  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 W=b<"z]RE  
4Uz1~AuNxb  
FyD^\6/x  
5'iJN$7  
  小结 |]=. ^  
:eIPPh|\  
Xc)V;1  
vwy10PlqL  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 kg@D?VqJP  
P(iZGOKUs=  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

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