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

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

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 X?6E0/r&9  
mT]+wi&  
\R!.VL3Tx$  
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 O $dcy!  
0QzUcr)3+  
Oup5LH!sW  
4}i2j  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 qcN{p7=0  
] lBe   
~* R:UTBtw  
A/bxxB7w  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 VV_Zrje  
[G.4S5FX.]  
0<g;g%   
eA4dDKX+  
  一、常见错误1# :多次拷贝字符串 xg:r5Z/|)  
25bbuhss  
D\~s$.6B  
f82$_1s^  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 W|~Jl7hs8Q  
#=}dv8  
=O~ J  
It5U=PU  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: `zRE$O  
cImOZx  
jCJbmEfo9@  
^*6So3  
String s = new String ("Text here"); Yg @&@S]  
]1 V,_^D  
">{Ruv}$  
4jWzYuI&J  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: "ITC P<+  
`5HFRgL`.  
0n FEPMO  
,H_b@$]n8  
String temp = "Text here"; G<F+/Oi&DX  
String s = new String (temp); E?VPCx  
0r4,27w  
P M x`P B  
d65fkz==A)  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: \t pJ   
PZT]H?  
*\-R&8  
asT/hsSNS  
String s = "Text here"; {2A| F{7>  
zRO-oOJ  
%i!=.7o.  
.Lwp`{F/  
  二、常见错误2#: 没有克隆(clone)返回的对象 .J/x@  
|JUb 1|gi  
:Dh\  
y v$@i A  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: |8QXjzH  
2H,^i,  
sIVVF#0}]  
JYAtQTOR  
import java.awt.Dimension; `6R.*hq  
/***Example class.The x and y values should never*be negative.*/ [lU0TDq  
public class Example{ MD"a%H#p  
  private Dimension d = new Dimension (0, 0); $0kuR!U.N  
  public Example (){ } qdM=}lbc  
gs xT  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ 5l(8{,NDt  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ X0QY:?  
   if (height < 0 || width < 0) D.!ay>o0#  
    throw new IllegalArgumentException(); 5B|&+7dCw  
    d.height = height; P!6 v0ezN  
     d.width = width;  (0wQ [(  
  } CMcS4X9/}  
34D7qR  
  public synchronized Dimension getValues(){ [!g$|   
   // Ooops! Breaks encapsulation iXF iFsb  
   return d; %OV)O-  
  } jX9{Ki"  
} g9T9TQ-O  
C >@T+xOZ  
1X ?9Ji)h  
m L#%H(  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: lmsO 6=I4F  
35;UE2d)<  
x|7vN E=Q  
H3}eFl=i2  
Example ex = new Example(); z1K}] z%  
Dimension d = ex.getValues(); 7EfLd+  
d.height = -5; =6sA49~M  
d.width = -10; M1Frn n  
lc:dKGF6  
(plsL   
E43Gk!/|(  
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 Wl29xY}`{!  
k@[P\(a3b  
*X_-8 ^~  
-(Zi  
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 #4yh-D"  
O<*l"fw3  
b`9J1p.;  
,k9@%{4 l  
  更好的方式是让getValues()返回拷贝: EMTAl;P  
7_=7 ;PQ<  
#"T< mM7  
Np.] W(  
public synchronized Dimension getValues(){ ORc20NFy7  
return new Dimension (d.x, d.y); F0D7+-9[  
} J{69iQ  
Yn~N;VUA  
8et*q3D7`  
brdfj E8  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 bG|aQ2HW  
odPdWV,&*  
&'mq).I2  
WGK:XfOBQ  
  三、常见错误3#:不必要的克隆 . `ND  
QE#Ar8tU  
+WH|nV~lQ  
#W]4aZ1  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: I,nW~;OV0  
9B&fEmgEc?  
c; MF  
=*[98%b   
/*** Example class.The value should never * be negative.*/ .{=|N8*py8  
public class Example{ en5sqKqh+  
  private Integer i = new Integer (0); q!qOy/}D  
  public Example (){ } Ir,3' G  
e7$ZA#A_5v  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ cu@i;Hb@  
  public synchronized void setValues (int x) throws IllegalArgumentException{ 4/Mi-ls_  
   if (x < 0) IAl X^6s*  
    throw new IllegalArgumentException(); j "^V?e5  
    i = new Integer (x); yu~o9  
  } AeZ__X  
O'WB O"  
  public synchronized Integer getValue(){ y8!#G-d5  
   // We can’t clone Integers so we makea copy this way. T, z80m}  
   return new Integer (i.intValue()); T'K6Q cu  
  } $;V?xZm[  
} zxo" +j4Ym  
^p}S5,  
drM@6$k  
oPbxe  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 [bK5q;#U4  
}5nVZ;  
"R!) "B==  
'f "KV|  
  方法getValue()应该被写为: &yabxl_  
e  -yL  
K8R}2K-Y  
m 4r!Ck|  
public synchronized Integer getValue(){ </jzM?i  
// ’i’ is immutable, so it is safe to return it instead of a copy. zZhA]J  
return i; GdlzpBl  
} eF06B'uL  
70MSP;^  
?6#F9\  
)*CDufRFz  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: [dXpz^Co  
^tr?y??k  
zT< P_l  
q; n  
  ?Boolean `Vf k.OP  
   ?Byte gx55.}  
   ?Character xl]1{$1M  
   ?Class !VzbNJ&'  
   ?Double !,0%ZG}]7  
   ?Float |GLh|hr  
   ?Integer uex m|5|  
   ?Long DDwj[' R  
   ?Short AY B~{  
   ?String /E32^o|,>  
   ?大部分的Exception的子类 *%#Sa~iPo  
zF([{5r[!)  
Bokpvd-c7  
knS(\51A  
 四、常见错误4# :自编代码来拷贝数组 |Q\O% cb  
VUF$,F9  
h't! 1u  
qrw"z iW  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: ih[!v"bv  
$.0l% $7  
Pqtk1=U  
p3q >a<  
public class Example{ {pR4+g  
  private int[] copy; ~ 7^#.  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ xaw)iC[gI{  
  public void saveCopy (int[] data){ (]}52%~  
   copy = new int[data.length]; v|K'M,E  
   for (int i = 0; i < copy.length; ++i) 5Kw$QJ/  
    copy = data; /9 ^F_2'_  
  } }NgevsV>;  
} 6oA2"!u^w  
I%Yeq"5RB  
x[dR5  
YK V?I   
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: i .GJO +K  
1I#]OY#>  
0g{`Qd  
j YVR"D;  
void saveCopy (int[] data){ JsA.j qkB  
  try{ [zw0'-h.  
   copy = (int[])data.clone(); p\).zuEf.  
  }catch (CloneNotSupportedException e){ `m_ ('N  
   // Can’t get here. TilCP"(6D  
  } a^5.gfzA  
} |~d8j'rt  
/T\'&s3D+  
.VG5 / 6zp  
vS1#ien#  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: 02RZ>m+  
H~ `JAplr  
^lP;JT?  
U-6pia /o  
static int[] cloneArray (int[] data){ xro%AM  
  try{ }1}L&M@  
   return(int[])data.clone(); u$%;03hJ  
  }catch(CloneNotSupportedException e){ pcC/$5FQ  
   // Can’t get here. Wq"5-U;:w  
  } Y A:!ULzR*  
} OC5\3H  
nb|KIW  
M8y:FDX  
7ZR0cJw;  
  这样的话,我们的saveCopy看起来就更简洁了: ] i:WP2  
DPg\y".4Y&  
d [f,Nu'  
aJ3.D  
void saveCopy (int[] data){ l6~wm1vO  
  copy = cloneArray ( data); _rakTo8BY  
} ui .riD[,O  
Q| _e=  
A1p87o>  
]Dd}^khv  
  五、常见错误5#:拷贝错误的数据 ur@"wcl"V  
U'oFW@Y;h  
'L5ih|$>  
oQL$X3S  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: s.IYPH|pn  
`iZ){JfAH  
WFm\ bZ.  
30fqD1_{  
import java.awt.Dimension; Bid+,,  
/*** Example class. The height and width values should never * be LLD#)Jl{?  
negative. */ 7) zF8V  
public class Example{ |EZ\+!8N:{  
  static final public int TOTAL_VALUES = 10; 3bBCA9^se  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; {"vTaY@  
  public Example (){ }  &peUC n  
/BQB7vL  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ A8T75?lL(  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ MY w3+B+Jj  
   if (height < 0 || width < 0) uWjSqyb:  
    throw new IllegalArgumentException(); +L hV4@zC  
    if (d[index] == null) /3KPK4!m  
     d[index] = new Dimension(); |x+g5~$  
     d[index].height = height; !eP)"YWI3  
     d[index].width = width; $_Kcm"oj  
  } 6+LBs.vl}  
  public synchronized Dimension[] getValues() E'iN==p_:  
   throws CloneNotSupportedException{ S9kA69O  
    return (Dimension[])d.clone(); N?j#=b+D  
  } AV]7l}-  
} ; nc3O{rU  
LM2S%._cj;  
`P *wz<  
es!>u{8)  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: X6-;vnlKN  
ANuO(^  
bB+ 4  
8$~^-_>n/  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ &G$K. q  
  Dimension[] copy = (Dimension[])d.clone(); UNF@%O4_T  
  for (int i = 0; i < copy.length; ++i){ G<W;HMj2  
   // NOTE: Dimension isn’t cloneable. m'PU0x  
   if (d != null) T8W;Lb9hQ  
    copy = new Dimension (d.height, d.width); E]c0+rh~  
  } pZ)N,O3  
  return copy; FByA4VxB  
}  \<u  
}MIg RQ9  
X0 ^~`g  
EN/r{Cm$B  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: mhW*rH*m  
i TLX=.M  
ncdj/C  
Ux-i iH#s  
public void store (int[] data) throws CloneNotSupportedException{ S.R|Bwj}(Y  
  this.data = (int[])data.clone(); }'WEqNuE  
  // OK sL4j@Lt  
} xRbtiFk9H  
yN{TcX  
Csf!I@}Z  
wO&+Bb\=  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: F S!D  
21sXCmYR,t  
5*\]F}  
 %X* *(  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ r) g:-[Ox9  
  this.data = (int[][])data.clone(); // Not OK! V/Q/Ujgg  
} ((AIrE>Rr  
public void rightStore (int[][] data){ @ D.MpM}~  
  // OK! `Rx\wfr}  
  this.data = (int[][])data.clone(); %V|n2/O Y  
  for (int i = 0; i < data.length; ++i){ /2>.*H_2  
   if (data != null) NnRX0]  
    this.data = (int[])data.clone(); &a!MT^anA~  
  } &cZl2ynPi  
} S1a6uE  
-8Q}*Z  
~v6]6+   
})umg8s  
]{ir^[A6  
   六、常见错误6#:检查new 操作的结果是否为null Cs'<;|r(  
td5! S]  
Q" G;L  
^t Y _ q  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: Y2aN<>f  
xQDWnpFc  
#<DS-^W!  
W|(U} PrC  
Integer i = new Integer (400); dLbSvK<(I  
if (i == null) 0b}.!k9  
throw new NullPointerException(); V*gh"gZ<  
PVaqKCj:6W  
5S 4 Bz  
VQ8Q=!]  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 4u= v  
2= zw !  
,t +sw4  
,}/6Za  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 Gz:ell$  
Slv91c&md,  
 七、常见错误7#:用== 替代.equals c2wgJH!g  
c0Yc~&RF  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: \: Q)X$6  
-"6Z@8=  
ttA'RJ  
&AnWMFo  
int x = 4; |ZG0E  
int y = 5; [LM9^*sG2V  
if (x == y) 1#KBf[0  
  System.out.println ("Hi"); ^&KpvQNW_  
// This ’if’ test won’t compile. ]Jo}F@\g  
if (x.equals (y)) @a (-U.CZ  
  System.out.println ("Hi"); ldt]=Sqy  
AP+%T   
/vs79^&  
Ch_eK^ g1  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 (,D:6(R7t  
Xi0fX$-,  
g(dReC  
ej,R:}C%`  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 ;)q"X>FMZe  
-8yN6 0|  
hv*XuT/  
{uurLEe?  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 3.6Gh|7  
1D1qOg"LE  
:!wl/X ~  
*tfD^nctO  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 vZ1?4hG  
X#tCIyK,nV  
Y|S>{$W  
V[0 ZNT&  
  八、常见错误8#: 混淆原子操作和非原子操作 &qP0-x)  
bnZ H  
nP_)PDTFp  
O9rA3qv B  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: sGx3O i   
5 zz">-Q !  
>qZl s'  
gxmY^" Jy  
public class Example{ 06z+xxCo  
  private int value; // More code here... a SMoee@!  
  public void set (int x){ z"-oD*ICw  
   // NOTE: No synchronized keyword PYTwyqS  
   this.value = x; ;;+h4O )  
  } #gVWLm<  
} SqZ .}s  
Qna*K7kv  
{DZ xK(  
_& r19pY  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: [eFJ+|U9  
.DM-&P  
K>TEt5  
0 \V)DV.i  
public void increment (){ =#vJqA  
  // This is effectively two or three instructions: _9'hmej  
  // 1) Read current setting of ’value’. qWJHb Dd  
  // 2) Increment that setting. V''fmWo7  
  // 3) Write the new setting back. |g'ceG-  
  ++this.value; 3H|drj:KV  
} ,(&Fb~r]  
M 5$JBnN  
13pu{Xak  
i,t!17M:  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: Ns]$+|  
jig3M N  
HPg%v |  
N`~f77G  
public synchronized void increment (){ F\^\,hy  
  ++this.value; ]Ljb&*IEj  
} Q\>mg*79  
X#HH7V>  
lOM8%{.'_x  
eAStpG"*  
  九、常见错误9#:在catch 块中作清除工作 <s%Ft  
 : 76zRF  
8`6G_:&X  
2A:&Cqo  
  一段在catch块中作清除工作的代码如下所示: WNt':w^_  
j{D tjV8  
m&s>Sn+  
AD+OQLG]`  
OutputStream os = null; 7 IJn9b  
try{ +d7 Arg!m  
  os = new OutputStream (); aKE`nA0\B  
  // Do something with os here. ,U)&ny  
  os.close(); p:W{c/tV  
}catch (Exception e){ 5nTcd@lX  
  if (os != null) !a25cm5ys  
  os.close(); \XwC|[%P  
} !c dY`f6x  
K-@\";whF  
"$D'gS oYe  
/nv+*+Q?d  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: : dNJ2&kJ  
Gpi_p  
,Xr`tQ<@  
bI`JG:^b  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 0 /9 C=v  
?1zGs2Qs  
^;F5ymb3U  
+25=u|#4r  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 e-OKv#]  
1z0|uc  
8I Ip,#%v  
OCq5}%yU&i  
  3.close()可能会抛出异常。 Y]5spqG  
' sNiJ>  
.Z#/%y3S  
ec/>LJDX7  
  上面代码的一个更优版本为: 29CzG0?B  
K|OPtYeb  
z 2jC48~  
Ftd,dqd  
OutputStream os = null; 7WUv  O  
try{ nA{yH}D4  
  os = new OutputStream (); _!!Fg%a5"R  
  // Do something with os here. 9_?e, Q  
}finally{ e6bh,BwgQq  
  if (os != null) BoST?"&}'  
   os.close(); W-gu*iZ6&  
} Z`86YYGK  
TI\xCIH  
n>7aZ1Qa  
/h{Rf,H  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 wOCAGEg  
gFrNk Uqp  
0TSB<,9a[  
#ti%hm  
  十、常见错误10#: 增加不必要的catch 块 BvH?d]%  
t%J1(H  
}}ic{931  
*/_'pt  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 ^\kH^   
Jz3,vV fQ:  
!s?SI=B8  
FvYciU!  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。 t K/.9qP  
L &hw- .Q  
>fth iA  
FvG?%IFM  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: nm& pn*1  
MB $aN':  
<VQ)}HW;k  
uv<_.Jq]  
try{ zx,9x*g  
  // Nifty code here So8 Dwz?  
}catch(Exception e){ psc Fb$b  
  throw e; i;s;:{cn  
}finally{ kU=U u>  
  // Cleanup code here m(}}%VeR"z  
} `C C=?E  
&6 <a<S  
h_+  
7S&$M-k  
  不必要的catch块被删除后,上面的代码就缩短为: 6>)nkD32g  
QxGcRlpLK  
%[s%H)e)  
R dwt4A+  
try{ ^jUw4Dj~-q  
  // Nifty code here PgGUs4[  
}finally{ -{8K/!  
  // Cleanup code here #.[eZ[  
} KX 7 fgC  
>C!^%e;m  
{j;` wN  
|2@*?o"ll  
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 ; :q  
tq3Rc}  
%>_6&A{K,d  
@\XeRx;  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 Ie(.T2K  
 o kA<  
%D8.uGsh  
3+s$K(%I  
  小结 a!-J=\>9  
noL9@It0  
{>9ED.t  
|3yG  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 #0Y_!'j  
H,5]w\R6\  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

您目前还是游客,请 登录注册
温馨提示:欢迎交流讨论,请勿纯表情、纯引用!
认证码:
验证问题:
3+5=?,请输入中文答案:八 正确答案:八