今天写一个很简单的背包数据结构的实现,却被一个小问题难住了。在add一个新元素的方法中,开始时我是这么写的:
- public boolean add(Object newEntry) {
- if (isBagFull())
- doubleCapacity();
- entry[size ++] = newEntry;
- return true;
- }//end add
可是这是一种很不安全的写法。比如客户想把一个newEntry对象添加到两个背包中,那么这两个背包中的对象实际上是同一个对象。因此在add方法中最好能复制一份newEntry, 把让entry[size]引用newEntry的备份。
而newEntry是Object 类型,不能直接调用newEntry.clone()返回一个备份。怎么办呢?在网上搜啊搜,才知道我的疑问来自于浅复制和深复制的概念及实现。有一篇文章已经说得很好了:Java中的深复制与浅复制 http://java.chinaitlab.com/oop/716567.html 。下面总结一下该文章的内容以及我的理解。
浅复制就是引用不同而对象相同,深复制就是对象也不同。clone() 方法十分诡异,一个类要implements Clonable, 然后覆盖clone() 方法,在clone() 方法中调用super.clone(), 才能实现深复制。如果不实现Clonable接口,则仍然是浅复制。我认为此方法很麻烦,比如我想复制一个类对象,就得把这个类的所有域的类、域的类的域 的类...都搞成Clonable。更重要的是,这个方法解决不了当前的问题:我要复制一个Object。
另一种深复制的方法是利用“序列化”。把对象写到一个Byte流中,再读出来,达到复制的效果:
- public static Object copy(Object oldObj){
- Object obj = null;
- try{
- //Write the object out to a byte array
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- ObjectOutputStream oOut = new ObjectOutputStream(bOut);
- oOut.writeObject(oldObj);
- oOut.flush();
- oOut.close();
- //Retrieve an input stream from the byte array and read a copy of the object back in
- ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
- ObjectInputStream oIn = new ObjectInputStream(bIn);
- obj = oIn.readObject();
- oIn.close();
- }catch(IOException e){
- e.printStackTrace();
- }catch(ClassNotFoundException e){
- e.printStackTrace();
- }
- return obj;
啊哈,其实一个Object不就是一堆字节流吗,类的结构决定了“划分”字节流的方式,从而成了某个类的对象。
通过这次折腾,发现自己Java学得太菜了,对引用的认识太浅。要走的路还很长,继续折腾吧!