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

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

级别: 终身会员
发帖
3743
铜板
8
人品值
493
贡献值
9
交易币
0
好评度
3746
信誉值
0
金币
0
所在楼道
代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效。由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug。并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那些能够容易在阅读代码的时候发现的错误,这些错误往往不容易通过机器上的测试识别出来。本文就常见的Java代码中容易出现的问题提出一些建设性建议,以便您在审查代码的过程中注意到这些常见的细节性错误。 _T=";NSa  
^}:0\;|N  
H)y_[:[  
  通常给别人的工作挑错要比找自己的错容易些。别样视角的存在也解释了为什么作者需要编辑,而运动员需要教练的原因。不仅不应当拒绝别人的批评,我们应该欢迎别人来发现并指出我们的编程工作中的不足之处,我们会受益匪浅的。 rxZk!- t)L  
%:dd#';g  
;2^zkmDM  
0/cgOP!^  
 正规的代码审查(code inspection)是提高代码质量的最强大的技术之一,代码审查?由同事们寻找代码中的错误?所发现的错误与在测试中所发现的错误不同,因此两者的关系是互补的,而非竞争的。 6vzvH  
)ub!tm  
mXsSOAD<  
5bol)Z9BO  
  如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍。在这篇文章中,我列出了11个Java编程中常见的错误。你可以把这些错误添加到你的代码审查的检查列表(checklist)中,这样在经过代码审查后,你可以确信你的代码中不再存在这类错误了。 =w:H9uj6F  
t*Z-]P  
?wjk=hM2  
0\eSiXs  
  一、常见错误1# :多次拷贝字符串 Cq-99@&;  
Eok8+7g0&  
z_8Bl2tl  
=CL,+  
  测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可改变的,因此不需要拷贝它。最常用的不可变对象是String。 psS^  
$-E<{   
"'>fTk_  
r8A'8g4cM  
  如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: FtWO[*#  
O_5;?$[m  
e0#{'_C  
DnN+W  
String s = new String ("Text here"); "k),;1  
j}8^gz]  
a &`^M  
g7eI;Tpv  
  但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: QEmktc1 7  
E#kH>q@K`$  
5F :\U  
qzk]9`i1:  
String temp = "Text here"; dO-Zj#%7z8  
String s = new String (temp); dtXtZ!g2  
s GrI%3[e"  
%H}M[_f  
2m72PU<.  
  但是这段代码包含额外的String,并非完全必要。更好的代码为: dE (d'*+a  
C?\HB#41  
9g$fFO  
g](&H$g  
String s = "Text here"; Af^9WJ  
l8lJ &  
*LvdrPxU=  
UG6\OgkL+  
  二、常见错误2#: 没有克隆(clone)返回的对象 +ERuZc$3,  
paxZlA o  
#EH\Q%  
TI8E W  
  封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便??Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: 0bGQO&s [  
C{6m?6  
2J` LZS  
2[KHmdgtB  
import java.awt.Dimension; UZgrSX {  
/***Example class.The x and y values should never*be negative.*/ V{rQ@7SE  
public class Example{ q?f-h<yRQ  
  private Dimension d = new Dimension (0, 0); -BsZw. 7P  
  public Example (){ } `Cu9y+t  
fY|vq amA;  
  /*** Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ pFwe&_u]  
  public synchronized void setValues (int height,int width) throws IllegalArgumentException{ YIYuqtnSJ  
   if (height < 0 || width < 0) >EgMtZ88.<  
    throw new IllegalArgumentException(); W7IAW7w8U  
    d.height = height; rE\&FVx  
     d.width = width; *`tQX$F  
  } U.|0y=  
^9|&w.:@Q  
  public synchronized Dimension getValues(){ .GW)"`HbU  
   // Ooops! Breaks encapsulation eBe5H =I@  
   return d; "fSK7%BP  
  } >lugHF$G  
} X`I=Z ysB  
|@)jS.Bn  
{_4zm&  
 o7AI  
  Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: `1R[J4e  
+ZRm1q   
o:Tpd 0F  
McvLU+  
Example ex = new Example(); iyMoLZ5  
Dimension d = ex.getValues(); ;i3C  
d.height = -5;  1oG'm  
d.width = -10; *(VwD)*  
V_)465g  
xf{=~j/L  
,9 .NMFn  
  现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。 "+BuFhSLf  
PC)V".W 1  
PS??wlp7  
M5]$w]Ny9  
  不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。 5eas^Rm  
lq27^K  
W1O m$S1  
@h7 i;Ok  
  更好的方式是让getValues()返回拷贝: j,N,WtE  
I4zm{ 1g  
QFEc?sEe  
l{_1`rC'  
public synchronized Dimension getValues(){ &|Vzo@D(!  
return new Dimension (d.x, d.y); }z2K"eGt  
} ]tEH`Kl  
o(xt%'L`t  
vu/P"?F  
LeMo")dk\  
  现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。 jL~. =QD  
8;Df/ %  
bj 0-72V  
W-vEh  
  三、常见错误3#:不必要的克隆 X""}]@B9z  
~G~:R  
0"`|f0}c  
"=9)|{=m  
  我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: @z(s\T  
m pM,&7}  
NW?h~2  
Oxh . &  
/*** Example class.The value should never * be negative.*/ 97VS xhr  
public class Example{ [JVUa2Sm  
  private Integer i = new Integer (0); T- lHlm  
  public Example (){ } >zv}59M  
UC"_#!3  
  /*** Set x. x must be nonnegative* or an exception will be thrown*/ [b@9V_  
  public synchronized void setValues (int x) throws IllegalArgumentException{ F#7A6|  
   if (x < 0) IQ9Rvnna  
    throw new IllegalArgumentException(); ~ponYc.Y  
    i = new Integer (x); .BZ3>]F3<  
  } PvS\  
1?T^jcny:M  
  public synchronized Integer getValue(){ 4i Z7BD  
   // We can’t clone Integers so we makea copy this way. |_wbxdq  
   return new Integer (i.intValue()); `"j_]  
  } :FI 4GR*?  
} X FvPc  
5E\&O%W"  
ixo?o]Xb`  
@*~cmf&FIQ  
  这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样,一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 8x<; AL|`  
|'12Kv]#Xa  
</7?puVR  
VXu1Y xY  
  方法getValue()应该被写为: >J@hqW  
`T$CUlt6  
4031~A8  
3 e<sNU?  
public synchronized Integer getValue(){ Vu1X@@z  
// ’i’ is immutable, so it is safe to return it instead of a copy. {@<EVw  
return i; 9vz"rHV  
} {@`Z`h" N  
E3o J;E  
+J%9%DqF  
dK?vg@|'  
  Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: [ncOtDE  
 Q ,)}t  
Nn|~ :9#  
/s^O M`5  
  ?Boolean 1$ ~W~O  
   ?Byte Q::6|B,G  
   ?Character }\)O1  
   ?Class ]!04L}hy|P  
   ?Double ?hwT{h  
   ?Float '-m )fWf  
   ?Integer 6/eh~ME=  
   ?Long F;_L/8Ov1  
   ?Short  -!z,t7!  
   ?String :g=z}7!s  
   ?大部分的Exception的子类 Z3 $3zyi  
- +=+W  
7\1bq&a<  
R} aHo0r  
 四、常见错误4# :自编代码来拷贝数组 <hbxerg  
fu?Y'Qet  
RzLbPSTQ  
<xQHb^:  
  Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,问题在于如下的循环用三行做的事情,如果采用Object的clone方法用一行就可以完成: 6tg0=_c  
F;^GhiQVS  
$^4URH  
C@L8,Kj ~.  
public class Example{ GT} =(sD L  
  private int[] copy; !`%3?}mv,  
  /*** Save a copy of ’data’. ’data’ cannot be null.*/ VXtW{*{"  
  public void saveCopy (int[] data){ C~dD'Tq]  
   copy = new int[data.length]; i@}/KT  
   for (int i = 0; i < copy.length; ++i) 5%n  
    copy = data; W{2(fb  
  } Q>}*l|Ci  
} X}$uvB}+>  
[#emm1k  
3<nd;@:-  
NbtNu$%t  
  这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: O7z -4r  
^s&1,  
2_]"9d4  
@4N@cM0   
void saveCopy (int[] data){ K)C9)J<  
  try{ H%:~&_D  
   copy = (int[])data.clone(); H,H=y},  
  }catch (CloneNotSupportedException e){ m# ]VdO'f  
   // Can’t get here. /HmD/E\  
  } f._FwD  
} Z ^tF  
} 1 >i  
W\?_o@d  
r-$SF5uv  
  如果你经常克隆数组,编写如下的一个工具方法会是个好主意: \Q+<G-Kb.  
Gmi$Nl!~  
{$ghf"  
C 4 &1M  
static int[] cloneArray (int[] data){ b4$-?f?V  
  try{ {b^JH2,  
   return(int[])data.clone(); qh)o44/ $  
  }catch(CloneNotSupportedException e){ dfBTx6/F  
   // Can’t get here. x xh(VQdg  
  } U`es n?m!  
} 4EiEE{9V  
N| dwuBW  
[p+6HF  
e!67Na0X(  
  这样的话,我们的saveCopy看起来就更简洁了: p9[J 9D3~  
> T,^n {_v  
&?=UP4[oif  
d&x1uso%L  
void saveCopy (int[] data){ 5};Nv{km^2  
  copy = cloneArray ( data); )kSE5|:pi  
} b=!G3wVw<  
mV0.9pxS  
09{B6l6P  
n)(E 0h  
  五、常见错误5#:拷贝错误的数据 4{d!}R  
p<\yp<g  
`4& GumG  
(0Xgv3wd  
  有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工作,下面的代码与程序员的意图有偏差: U!L<v!$  
e?%Qv+)W  
!'()QtvC<  
P%v7(bqL4+  
import java.awt.Dimension; OYEL`!Q  
/*** Example class. The height and width values should never * be VQ/<MY C  
negative. */ BK>uJv-qU  
public class Example{ .r/6BDE"  
  static final public int TOTAL_VALUES = 10; {BBL`tg60  
  private Dimension[] d = new Dimension[TOTAL_VALUES]; Azun"F_f  
  public Example (){ } C~.7m-YW  
AKVll  
  /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ gu[3L  
  public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ 0i2ZgOJ  
   if (height < 0 || width < 0) DbdxHuKa>  
    throw new IllegalArgumentException(); cCd2f>EHw  
    if (d[index] == null) );*A$C9RA  
     d[index] = new Dimension(); `Tx1?]  
     d[index].height = height; :bx q%D%|o  
     d[index].width = width; OQ>r;)/  
  } Br2ZloJ@+  
  public synchronized Dimension[] getValues() Ldnw1xy  
   throws CloneNotSupportedException{ 2-9'zN0u  
    return (Dimension[])d.clone(); T.vkGB=QZ%  
  } 1'dL8Y  
} 6@TGa%:G  
$\xS~ w  
:?VM1!~ga  
kETu@la}  
  这儿的问题在于getValues()方法仅仅克隆了数组,而没有克隆数组中包含的Dimension对象,因此,虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象,但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。方法getValues()的更好版本为: g|r:+%,M  
Nb2]}; O  
ssv4#8p3  
<!#6c :(Q  
public synchronized Dimension[] getValues() throws CloneNotSupportedException{ =IH z@CU  
  Dimension[] copy = (Dimension[])d.clone(); !xm87I  
  for (int i = 0; i < copy.length; ++i){ $F!)S  
   // NOTE: Dimension isn’t cloneable. ;Jex#+H(:D  
   if (d != null) V&x6ru#  
    copy = new Dimension (d.height, d.width); J;pn5k~3  
  } K4Mv\!Q<8  
  return copy; d7+YCi?  
} ] Ma2*E !p  
gw0b>E8gZ&  
zT[[WY4  
] 8sVXZ  
  在克隆原子类型数据的多维数组的时候,也会犯类似的错误。原子类型包括int,float等。简单的克隆int型的一维数组是正确的,如下所示: Ij_Y+Mnl4:  
F2yc&mXyk  
|kL^k{=zV  
^Jb=&u$  
public void store (int[] data) throws CloneNotSupportedException{ wXv\[z L`  
  this.data = (int[])data.clone(); ln#Jb&u  
  // OK v%|^\A"V  
} rmj?jBKQU  
(^-i[aJY  
lPL>8.j  
n22k<@y  
  拷贝int型的二维数组更复杂些。Java没有int型的二维数组,因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。简单的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本同样的错误,因此应该避免这么做。下面的例子演示了在克隆int型二维数组时错误的和正确的做法: KS($S( Fi  
c0v;r4Jo#j  
Jrp{e("9  
F0O"rN{  
public void wrongStore (int[][] data) throws CloneNotSupportedException{ %/17K2g  
  this.data = (int[][])data.clone(); // Not OK! Yb8o`j+t  
} [bd fp a  
public void rightStore (int[][] data){ #<20vdc  
  // OK! yk1syN_  
  this.data = (int[][])data.clone(); IKhpe5}  
  for (int i = 0; i < data.length; ++i){ @G  0k+  
   if (data != null) RI_:~^nO{r  
    this.data = (int[])data.clone(); |EuWzhNAO  
  } R8a4F^{*  
} ]2kgG*^n"  
=vx iqRm  
*Z"9QX  
: E `N0UA  
bq5tEn  
   六、常见错误6#:检查new 操作的结果是否为null &DC o;Ij;  
Wb:jZ  
q.6$-w  
{8Jr.&Y2  
  Java编程新手有时候会检查new操作的结果是否为null。可能的检查代码为: nd(O;XBI  
Ay'2! K,I  
u(B0X=B  
V_JM@VN}Kk  
Integer i = new Integer (400); t0XM#9L  
if (i == null) 2 fp\s5%J}  
throw new NullPointerException(); WyH2` xxX  
$Yh7N5XH,  
OHixOI$O  
5bZf$$b  
  检查当然没什么错误,但却不必要,if和throw这两行代码完全是浪费,他们的唯一功用是让整个程序更臃肿,运行更慢。 #gbJ$1s  
`z<k7ig  
qiQS:0|_  
bV_@!KL$  
  C/C++程序员在开始写java程序的时候常常会这么做,这是由于检查C中malloc()的返回结果是必要的,不这样做就可能产生错误。检查C++中new操作的结果可能是一个好的编程行为,这依赖于异常是否被使能(许多编译器允许异常被禁止,在这种情况下new操作失败就会返回null)。在java 中,new 操作不允许返回null,如果真的返回null,很可能是虚拟机崩溃了,这时候即便检查返回结果也无济于事。 +qsNz*@p"  
W)^0~[`i  
 七、常见错误7#:用== 替代.equals Gj]*_"T  
?9#}p  
  在Java中,有两种方式检查两个数据是否相等:通过使用==操作符,或者使用所有对象都实现的.equals方法。原子类型(int, flosat, char 等)不是对象,因此他们只能使用==操作符,如下所示: VmM?KlC  
oTj9/r  
d4h1#MK  
n gA&PU  
int x = 4; swv 1>52{  
int y = 5; GaMiu! |,  
if (x == y) 9$7tB  
  System.out.println ("Hi"); HMT^gmF)  
// This ’if’ test won’t compile. F.i%o2P3  
if (x.equals (y)) y21zaQ  
  System.out.println ("Hi"); D~W1["[  
~ow_&ftlo  
D6 B(6 5Y  
I%]L  
  对象更复杂些,==操作符检查两个引用是否指向同一个对象,而equals方法则实现更专门的相等性检查。 )0Av:eF-+  
W$=MuF7R  
QEIu}e6b  
g+Z~"O]$M  
  更显得混乱的是由java.lang.Object 所提供的缺省的equals方法的实现使用==来简单的判断被比较的两个对象是否为同一个。 &Pu}"M$[MH  
1:S75~b-`  
QGE)Xn#_bN  
Z)B5g>  
  许多类覆盖了缺省的equals方法以便更有用些,比如String类,它的equals方法检查两个String对象是否包含同样的字符串,而Integer的equals方法检查所包含的int值是否相等。 -}nTwx:|5u  
^Wk.D-  
6j9P`#Lt  
i,jPULzyjk  
  大部分时候,在检查两个对象是否相等的时候你应该使用equals方法,而对于原子类型的数据,你用该使用==操作符。 B\BxF6 y  
^W-03  
,Q~C F;qe  
^i}*$ZC72  
  八、常见错误8#: 混淆原子操作和非原子操作 |` gSkv  
ajFSbi)l  
!e*BQ3  
^ s< p5V  
  Java保证读和写32位数或者更小的值是原子操作,也就是说可以在一步完成,因而不可能被打断,因此这样的读和写不需要同步。以下的代码是线程安全(thread safe)的: ,gHgb  
Tdvw7I-q  
6@_Vg~=S  
g:bw;6^ u  
public class Example{ ^M60#gJ  
  private int value; // More code here... W#1t%hT$  
  public void set (int x){ {J-kcD!bz`  
   // NOTE: No synchronized keyword p-QD(+@M  
   this.value = x; fyat-wbb  
  } K1c@]]y)  
} noz&4"S.{  
7U_~_yb  
G&FA~c  
_\M:h+^  
  不过,这个保证仅限于读和写,下面的代码不是线程安全的: OEc$ro=m*  
:n36}VG|  
>% a^;gk(  
Z3Le?cMt^  
public void increment (){ |1vi kG8  
  // This is effectively two or three instructions: _B4H"2}[Y  
  // 1) Read current setting of ’value’. {VOLUC o 4  
  // 2) Increment that setting. ZsjDe{TH  
  // 3) Write the new setting back. }Xv2I$J  
  ++this.value; @?,iy?BSG  
} `8$gaA*  
~x`BV+R  
afEhC0j  
'{9nQ DgT  
  在测试的时候,你可能不会捕获到这个错误。首先,测试与线程有关的错误是很难的,而且很耗时间。其次,在有些机器上,这些代码可能会被翻译成一条指令,因此工作正常,只有当在其它的虚拟机上测试的时候这个错误才可能显现。因此最好在开始的时候就正确地同步代码: 1muB* O  
'yG9Rt  
z& !n'N<C  
(9bFIvMc  
public synchronized void increment (){ !9+xKr99  
  ++this.value; k!Y7 Rc{"  
} D,Ft*(|T  
5x";}Vp>P  
0. _)X  
^F @z +q  
  九、常见错误9#:在catch 块中作清除工作 /DPD,bA  
+[$d9  
5e^t;  
0zR4Kj7EE  
  一段在catch块中作清除工作的代码如下所示: RGrra<  
Z/nTI 0N{  
D;%(Z!  
Vo*38c2  
OutputStream os = null; *T(z4RVg  
try{ g~EJja;  
  os = new OutputStream (); FSnF>3kj-  
  // Do something with os here. WZkAlg7Z  
  os.close(); lFMQT ;  
}catch (Exception e){ 9/N=7<$  
  if (os != null) Hk)IV"[R  
  os.close(); w#EP`aM2$=  
} |y+<|fb,a  
'urn5[i  
=?Y%w%2  
CT1)tRN  
  尽管这段代码在几个方面都是有问题的,但是在测试中很容易漏掉这个错误。下面列出了这段代码所存在的三个问题: fhCMbq4T  
\bJ,8J1C  
4,D$% .  
W10=SM}  
  1.语句os.close()在两处出现,多此一举,而且会带来维护方面的麻烦。 24u;'i-y5  
{%WQQs  
y8/ 7@qw  
!F3Y7R  
  2.上面的代码仅仅处理了Exception,而没有涉及到Error。但是当try块运行出现了Error,流也应该被关闭。 tz0_S7h  
xE+Nz5F  
n_}=G RR  
IBYRuaEB  
  3.close()可能会抛出异常。 vb 2mY  
}%z {tn  
px!lJtvgo  
9|19ia@[\  
  上面代码的一个更优版本为: 8*O]  
9H$$Og  
>0yx!Iao  
|TCHPKN  
OutputStream os = null; :{za[,  
try{ NYS |fa  
  os = new OutputStream (); {Vy2uow0  
  // Do something with os here. }cDw9;~D  
}finally{ laVqI|0q  
  if (os != null) :CH?,x^!@  
   os.close(); !?t#QD o  
} dW hU o\>=  
? OrRTRW  
zd1X(e<|{  
"YY6_qQR'  
  这个版本消除了上面所提到的两个问题:代码不再重复,Error也可以被正确处理了。但是没有好的方法来处理第三个问题,也许最好的方法是把close()语句单独放在一个try/catch块中。 o[C,fh,$  
}Yd7<"kp  
eJWcrVpn  
/b3b0VfF  
  十、常见错误10#: 增加不必要的catch 块 \^7D% a=;C  
TiiMX  
+:@lde]/p  
GabY xYK  
  一些开发者听到try/catch块这个名字后,就会想当然的以为所有的try块必须要有与之匹配的catch块。 9d7`R'  
RRGo$  
mj\]oWS7d  
!RX7TYf  
  C++程序员尤其是会这样想,因为在C++中不存在finally块的概念,而且try块存在的唯一理由只不过是为了与catch块相配对。 G[34:J  
;| (_;d  
[l;9](\8O  
>z&|<H%  
  增加不必要的catch块的代码就象下面的样子,捕获到的异常又立即被抛出: )n8(U%q$  
}u"iA^'Ot  
<[7 bUB  
(of=hzT^?  
try{ rGPFPsMQ]  
  // Nifty code here I$Z8]&m  
}catch(Exception e){ ANuIPF4NxP  
  throw e; 1Yj^N" =  
}finally{ P.G`ED|K!Y  
  // Cleanup code here ,Mt/*^|  
} ~zEBJgeyh  
|8xu*dVAp4  
@9yY`\"ed  
s*A#;  
  不必要的catch块被删除后,上面的代码就缩短为: rnB-e?>  
DEmU},<S  
<B,z)c  
p[kEFE,%  
try{ nP9zTa  
  // Nifty code here ko-:) z  
}finally{ NWK+.{s>m  
  // Cleanup code here ]xO`c  
} ``l7|b jJ  
|7 .WP;1  
JA .J~3  
sj@B0R=Qo  
  常见错误11#;没有正确实现equals,hashCode,或者clone 等方法 ^zdZ"\x  
Z_Tu* F  
gQXB=ywF  
0(+3w\_!  
  方法equals,hashCode,和clone 由java.lang.Object提供的缺省实现是正确的。不幸地是,这些缺省实现在大部分时候毫无用处,因此许多类覆盖其中的若干个方法以提供更有用的功能。但是,问题又来了,当继承一个覆盖了若干个这些方法的父类的时候,子类通常也需要覆盖这些方法。在进行代码审查时,应该确保如果父类实现了equals,hashCode,或者clone等方法,那么子类也必须正确。正确的实现equals,hashCode,和clone需要一些技巧。 XYeuYLut  
Aqi9@BH  
~_XJ v  
Q]9g  
  小结 x3dP`<   
9?4EM^ -  
 Fu@2gd  
V\C$/8v  
  我在代码审查的时候至少遇到过一次这些错误,我自己也犯过其中的几个错误。好消息是只要你知道你在找什么错误,那么代码审查就很容易管理,错误也很容易被发现和修改。即便你找不到时间来进行正规的代码审查,以自审的方式把这些错误从你的代码中根除会大大节省你的调试时间。花时间在代码审查上是值得的。 Y!M&8;>  
e!+_U C  
 
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
描述
快速回复

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