y); 3. }
现在, Example对象的内部状态就安全了。 调用者可以根据需要改变它所得到的拷贝的状态, 但是要修改Example 对象的内部状态,必须通过setValues()才可以。 三、常见错误3#:不必要的克隆 我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: 1. /*** Example class.The value should never * be negative.*/ 2. public class Example{
3. 4. 5. 6. 7.
private Integer i = new Integer (0); public Example (){ }
/*** Set x. x must be nonnegative* or an exception will be thrown*/ public synchronized void setValues (int x) throws IllegalArgumentException{
8. 9. 10. 11. 12. 13. 14. 15. 16. 17. }
if (x < 0) throw new IllegalArgumentException(); i = new Integer (x); }
public synchronized Integer getValue(){ // We can’t clone Integers so we makea copy this way. return new Integer (i.intValue()); }
这段代码是安全的,但是就象在错误1#那样,又作了多余的工作。Integer对象,就象String对象那样, 一旦被创建就是不可变的。因此,返回内部Integer对象,而不是它的拷贝,也是安全的。 方法getValue()应该被写为: 1. public synchronized Integer getValue(){ 2. // ’i’ is immutable, so it is safe to return it instead of a copy. 3. return i; 4. }
Java程序比C++程序包含更多的不可变对象。JDK 所提供的若干不可变类包括: > Boolean > Byte > Character > Class > Double > Float > Integer > Long > Short
> String > 大部分的Exception的子类 四、常见错误4# :自编代码来拷贝数组 Java允许你克隆数组,但是开发者通常会错误地编写如下的代码,
问题在于如下的循环用三行做的事情, 如果采用Object的clone方法用一行就可以完成: 1. public class Example{ 2. 3. 4. 5. 6. 7. 8. 9. } } private int[] copy; /*** Save a copy of ’data’. ’data’ cannot be null.*/ public void saveCopy (int[] data){ copy = new int[data.length]; for (int i = 0; i < copy.length; ++i) copy[i] = data[i];
这段代码是正确的,但却不必要地复杂。saveCopy()的一个更好的实现是: 1. void saveCopy (int[] data){ 2. 3. 4. 5. 6. 7. } try{ copy = (int[])data.clone(); }catch (CloneNotSupportedException e){ // Can’t get here. }
如果你经常克隆数组,编写如下的一个工具方法会是个好主意: 1. static int[] cloneArray (int[] data){ 2. 3. 4. 5. 6. 7. } try{ return(int[])data.clone(); }catch(CloneNotSupportedException e){ // Can’t get here. }
这样的话,我们的saveCopy看起来就更简洁了: 1. void saveCopy (int[] data){ 2. 3. } copy = cloneArray ( data);
五、常见错误5#:拷贝错误的数据
有时候程序员知道必须返回一个拷贝,但是却不小心拷贝了错误的数据。由于仅仅做了部分的数据拷贝工 作,下面的代码与
程序员的意图有偏差: 1. import java.awt.Dimension; 2. /*** Example class. The height and width values should never * be 3. negative. */ 4. public class Example{ 5. 6. 7. 8. 9. /*** Set height and width. Both height and width must be nonnegative * or an exception will be thrown. */ 10. public synchronized void setValues (int index, int height, int width) throws IllegalArgumentException{ 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. } } } public synchronized Dimension[] getValues() throws CloneNotSupportedException{ return (Dimension[])d.clone(); if (height < 0 || width < 0) throw new IllegalArgumentException(); if (d[index] == null) d[index] = new Dimension(); d[index].height = height; d[index].width = width; static final public int TOTAL_VALUES = 10; private Dimension[] d = new Dimension[TOTAL_VALUES]; public Example (){ }
这儿的问题在于getValues()方法仅仅克隆了数组