您的位置:首页 > 编程语言 > Java开发

think in java第十二章笔记

2014-08-03 16:01 435 查看
1.

public class Alias2 {
	int i;
	Alias2(int ii) {
		i = ii;
	}
	static void f(Alias2 handle) {
		handle.i++;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Alias2 x = new Alias2(7);
		System.out.println("x:"+x.i);
		System.out.println("Calling f(x)");
		f(x);
		System.out.println("x:"+x.i);
	}

}


若需要在一个方法调用期间修改一个参数,且不打算修改外部参数,就应在自己的方法内部***一个副本,从而保护那个参数。

不存在本地对象,只有本地句柄。然而有时仍需将对象当做“本地的”对待,使我们做出的改变只影响一个本地副本,不会对外面的对象造成影响。

2.若需修改一个对象,同时不想改变调用者的对象,就要***对象的一个副本。只需要简单的使用clone()方法即可。这个方法在基础类Object中定义成"protected"模式。但在希望克隆的任何衍生类中,必须将其覆盖为"public"模式。

3.

import java.util.*;

class Int {
	private int i;
	public Int(int ii) {
		i = ii;
	}
	public void increment() {
		i++;
	}
	public String toString() {
		return Integer.toString(i);
	}
}
public class Cloning {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Vector v = new Vector();
		
		for(int i = 0; i < 10; i++)
			v.addElement(new Int(i));
		
		System.out.println("v: "+v);
		
		Vector v2 = (Vector)v.clone();
		for(Enumeration e = v2.elements(); e.hasMoreElements(); ((Int)e.nextElement()).increment());
		System.out.println("v: "+v);
	}

}


clone()方法产生了一个Object,后者必须立即重新造型为正确类型。这个例子指出Vector的clone()方法不能自动尝试克隆Vector内包含的每个对象——由于别名问题,老的Vector和克隆的Vector都包含了相同的对象。这种情况叫做“简单复制”或者“浅层复制”,因为它只复制了一个对象的“表面”部分。实际对象除包含这个“表面”以外,还包括句柄指向的所有对象。

4.

尽管克隆方法是在所有类基本的Object中定义的,但克隆仍然不会在每个类里自动进行。这似乎有些不可思议,因为基础类方法在衍生类里是肯定能用的。如果想在一个类里使用克隆方法,唯一的办法就是专门添加一些代码,以保证克隆的正常进行。

为避免我们创建的每个类都默认具有克隆能力,clone()方法在基础类Object里得到了“保留”(设为protected)。

5.

import java.util.*;
class MyObject implements Cloneable {
	int i;
	MyObject(int ii) {
		i = ii;
	}
	public Object clone() {
		Object o = null;
		
		try {
			o = super.clone();
		}catch(CloneNotSupportedException e) {
			System.out.println("MyObject can't clone");
		}
		
		return o;
	}
	
	public String toString() {
		return Integer.toString(i);
	}
}
public class LocalCopy {
	static MyObject g(MyObject v) {
		v.i++;
		return v;
	}
	static MyObject f(MyObject v) {
		v = (MyObject)v.clone();
		v.i++;
		return v;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyObject a = new MyObject(11);
		MyObject b = g(a);
		
		if(a == b)
			System.out.println("a == b");
		else
			System.out.println("a != b");
		
		System.out.println("a = "+a);
		System.out.println("b = "+ b);
		
		MyObject c = new MyObject(47);
		MyObject d = f(c);
		
		if(c == d)
			System.out.println("c == d");
		else
			System.out.println("c != d");
		
		System.out.println("c = "+c);
		System.out.println("d = "+d);
	}

}


不管怎样,clone()必须能够访问,所以必须将其设为public。其次,作为clone()的初期行动,应调用clone()的基础版本。这里调用的clone()是Object内部预先定义好的。之所以能够调用它,是由于它具有protected属性,所以能在衍生的类访问。

Object.clone()会先检查原先的对象有多大,再为新对象腾出足够多的内存,将所有二进制位从原来的对象复制到新的对象。这叫做按位复制,而且按一般的想法,这个工作应该由clone()方法来做。

在Object.clone()正式开始操作前,首先会检查一个类是否实现了Cloneable接口。若未实现,Object.clone()就抛出一个异常,指出我们不能克隆它。

6.

根类中的clone()方法负责建立正确的存储容量,并通过“按位复制”将二进制位从原始对象中复制到新对象的存储空间。 实际需要调查出欲复制之对象的准确大小,然后复制那个对象。这个过程需要RTTI判断克隆的对象的实际大小。采用这种方式,clone()方法便可建立起正确数量的存储空间,并对那个类型进行正确的按位复制。

不管我们要做什么,克隆过程的第一个部分通常都应该是采用super.clone().通过进行一次准确的复制,这样做可为后续的克隆进程建立起一个良好的基础。随后,可采取另一些必要的操作,以完成最终的克隆。

7.

import java.util.*;
class DepthReading implements Cloneable {
	private double depth;
	public DepthReading(double depth) {
		this.depth = depth;
	}
	public Object clone() {
		Object o = null;
		try {
			o = super.clone();
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		
		return o;
	}
}

class TemperatureReading implements Cloneable {
	private long time;
	private double temperature;
	public TemperatureReading(double temperature) {
		time = System.currentTimeMillis();
		this.temperature = temperature;
	}
	public Object clone() {
		Object o = null;
		
		try {
			o = super.clone();
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		
		return o;
	}
}

class OceanReading implements Cloneable {
	private DepthReading depth;
	private TemperatureReading temperature;
	public OceanReading(double tdata, double ddata) {
		temperature = new TemperatureReading(tdata);
		depth = new DepthReading(ddata);
	}
	public Object clone() {
		OceanReading o = null;
		
		try {
			o = (OceanReading)super.clone();
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		
		o.depth = (DepthReading)o.depth.clone();
		o.temperature = (TemperatureReading)o.temperature.clone();
		
		return o;
	}
}
public class DeepCopy {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		OceanReading reading = new OceanReading(33.9, 100.5);
		OceanReading r = (OceanReading)reading.clone();
	}

}


通常可在一个能克隆的类里调用super.clone(),以确保所有基础类行动(包括Object.clone())能够进行。随后是为对象内每个句柄都明确调用一个clone();否则那些句柄会别名变成原始对象的句柄。构建器的调用也大致相同——首先构造基础类,然后是下一个衍生的构建器......以此类推,直到位于最深层的衍生构建器。区别在于clone()并不是构建器,所以没有办法实现自动克隆。为了克隆,必须由自己明确进行。

试图深层复制合成对象时会遇到一个问题。必须假定成员对象中的clone()方法也能依次对自己的句柄进行深层复制,依此类推。

OceanReading是由DepthReading和TemperatureReading对象合成而成的。为了对其进行深层复制,clone()必须同时克隆OceanReading内的句柄。为达到这个目标,super.clone()的结果必须造型成一个OceanReading对象(以便访问depth和temperature句柄).

8.

class Int2 implements Cloneable {
	private int i;
	public Int2(int ii) {
		i = ii;
	}
	public void increment() {
		i++;
	}
	public String toString() {
		return Integer.toString(i);
	}
	
	public Object clone() {
		Object o = null;
		try {
			o = super.clone();
		}catch(CloneNotSupportedException e) {
			System.out.println("Int2 can't clone");
		}
		return o;
	}
}

class Int3 extends Int2 {
	private int j;
	public Int3(int i) {
		super(i);
	}
}
public class AddingClone {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Int2 x = new Int2(10);
		Int2 x2 = (Int2)x.clone();
		x2.increment();
		
		System.out.println("x = "+x+", x2 = "+x2);
		Int3 x3 = new Int3(7);
		x3 = (Int3)x3.clone();
		
		Vector v = new Vector();
		for(int i = 0; i < 10; i++) {
			v.addElement(new Int2(i));
		}
		
		System.out.println("v: "+v);
		
		Vector v2 = (Vector)v.clone();
		for(int i = 0; i < v.size(); i++)
			v2.setElementAt(((Int2)v2.elementAt(i)).clone(), i);
		
		for(Enumeration e = v2.elements(); e.hasMoreElements();)
			((Int2)e.nextElement()).increment();
		System.out.println("v: "+v);
		System.out.println("v2: "+v2);
	}

}


Int3自Int2继承而来,并添加了一个新的基本类型成员int j。将Int2的clone()当做Int3的clone()调用时,它会调用Object.clone(),判断出当前操作的是Int3,并复制Int3内的所有二进制位。只要没有新增需要克隆的句柄,对Object.clone()的一个调用就能完成所有必要的复制——无论clone()是在层次结构多深的一级定义的。

对Vector进行深层复制的先决条件:在克隆了Vector后,必须在其中遍历,并克隆由Vector指向的每个对象。为了对Hashtable进行深层复制,也必须采取类似的处理。

9.

若在一个对象序列化以后再撤销对它的序列化,或者进行装配,那么实际经历的正是一个"克隆"的过程。

10.

public class Stringer {
	static String upcase(String s) {
		return s.toUpperCase();
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String q = new String("howdy");
		System.out.println(q);
		String qq = upcase(q);
		System.out.println(qq);
		System.out.println(q);
	}

}
q传递进入upcase()时,它实际是q的句柄的一个副本。该句柄连接的对象实际只在一个统一的物理位置处。句柄四处传递的时候,它的句柄就会得到复制。s只有在upcase()执行期间才会存在。upcase()完成后,本地句柄s便会消失,而upcase返回结果——还是原来那个字串,只是所有字符都变成了大写。当然,它返回的实际是结果的一个句柄。但它返回的句柄最终句柄最终是为一个新对象。

String类的对象被设计成“不可变”,就会发现类中能够修改String的每个方法都实际都创建和返回了一个崭新的String对象,新对象里包含了修改过的信息——原来的String是原封未动的。

由于String对象是不可变的,所以能根据情况对一个特定的String进行多次别名处理。因为它是只读的,所以一个句柄不可能会改变一些会影响其他句柄的东西。

对字符串来说,同志类叫做StringBuffer,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: