think in java第十二章笔记
2014-08-03 16:01
435 查看
1.
若需要在一个方法调用期间修改一个参数,且不打算修改外部参数,就应在自己的方法内部***一个副本,从而保护那个参数。
不存在本地对象,只有本地句柄。然而有时仍需将对象当做“本地的”对待,使我们做出的改变只影响一个本地副本,不会对外面的对象造成影响。
2.若需修改一个对象,同时不想改变调用者的对象,就要***对象的一个副本。只需要简单的使用clone()方法即可。这个方法在基础类Object中定义成"protected"模式。但在希望克隆的任何衍生类中,必须将其覆盖为"public"模式。
3.
clone()方法产生了一个Object,后者必须立即重新造型为正确类型。这个例子指出Vector的clone()方法不能自动尝试克隆Vector内包含的每个对象——由于别名问题,老的Vector和克隆的Vector都包含了相同的对象。这种情况叫做“简单复制”或者“浅层复制”,因为它只复制了一个对象的“表面”部分。实际对象除包含这个“表面”以外,还包括句柄指向的所有对象。
4.
尽管克隆方法是在所有类基本的Object中定义的,但克隆仍然不会在每个类里自动进行。这似乎有些不可思议,因为基础类方法在衍生类里是肯定能用的。如果想在一个类里使用克隆方法,唯一的办法就是专门添加一些代码,以保证克隆的正常进行。
为避免我们创建的每个类都默认具有克隆能力,clone()方法在基础类Object里得到了“保留”(设为protected)。
5.
不管怎样,clone()必须能够访问,所以必须将其设为public。其次,作为clone()的初期行动,应调用clone()的基础版本。这里调用的clone()是Object内部预先定义好的。之所以能够调用它,是由于它具有protected属性,所以能在衍生的类访问。
Object.clone()会先检查原先的对象有多大,再为新对象腾出足够多的内存,将所有二进制位从原来的对象复制到新的对象。这叫做按位复制,而且按一般的想法,这个工作应该由clone()方法来做。
在Object.clone()正式开始操作前,首先会检查一个类是否实现了Cloneable接口。若未实现,Object.clone()就抛出一个异常,指出我们不能克隆它。
6.
根类中的clone()方法负责建立正确的存储容量,并通过“按位复制”将二进制位从原始对象中复制到新对象的存储空间。 实际需要调查出欲复制之对象的准确大小,然后复制那个对象。这个过程需要RTTI判断克隆的对象的实际大小。采用这种方式,clone()方法便可建立起正确数量的存储空间,并对那个类型进行正确的按位复制。
不管我们要做什么,克隆过程的第一个部分通常都应该是采用super.clone().通过进行一次准确的复制,这样做可为后续的克隆进程建立起一个良好的基础。随后,可采取另一些必要的操作,以完成最终的克隆。
7.
通常可在一个能克隆的类里调用super.clone(),以确保所有基础类行动(包括Object.clone())能够进行。随后是为对象内每个句柄都明确调用一个clone();否则那些句柄会别名变成原始对象的句柄。构建器的调用也大致相同——首先构造基础类,然后是下一个衍生的构建器......以此类推,直到位于最深层的衍生构建器。区别在于clone()并不是构建器,所以没有办法实现自动克隆。为了克隆,必须由自己明确进行。
试图深层复制合成对象时会遇到一个问题。必须假定成员对象中的clone()方法也能依次对自己的句柄进行深层复制,依此类推。
OceanReading是由DepthReading和TemperatureReading对象合成而成的。为了对其进行深层复制,clone()必须同时克隆OceanReading内的句柄。为达到这个目标,super.clone()的结果必须造型成一个OceanReading对象(以便访问depth和temperature句柄).
8.
Int3自Int2继承而来,并添加了一个新的基本类型成员int j。将Int2的clone()当做Int3的clone()调用时,它会调用Object.clone(),判断出当前操作的是Int3,并复制Int3内的所有二进制位。只要没有新增需要克隆的句柄,对Object.clone()的一个调用就能完成所有必要的复制——无论clone()是在层次结构多深的一级定义的。
对Vector进行深层复制的先决条件:在克隆了Vector后,必须在其中遍历,并克隆由Vector指向的每个对象。为了对Hashtable进行深层复制,也必须采取类似的处理。
9.
若在一个对象序列化以后再撤销对它的序列化,或者进行装配,那么实际经历的正是一个"克隆"的过程。
10.
String类的对象被设计成“不可变”,就会发现类中能够修改String的每个方法都实际都创建和返回了一个崭新的String对象,新对象里包含了修改过的信息——原来的String是原封未动的。
由于String对象是不可变的,所以能根据情况对一个特定的String进行多次别名处理。因为它是只读的,所以一个句柄不可能会改变一些会影响其他句柄的东西。
对字符串来说,同志类叫做StringBuffer,
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,
相关文章推荐
- 看完think in java第8章后的想法以及对java 1.5以后版本泛型的学习笔记
- 读书笔记----THINK IN JAVA
- think in java -笔记
- Think in Java 笔记_Chapter20_1_Annocation基础语法
- Think In java 笔记一
- think in java第十二章读书笔记
- Think in java 第四章笔记
- 关于think in java学习笔记的说明
- Think in java学习笔记-第4章 初始化和清除
- Think in Java 笔记_Chapter20_2_Annocation和Junit
- think in java 学习笔记
- think in java - 第二章 学习笔记
- Think in java 学习笔记 ---- 阶段 1
- Think In Java 笔记
- Think in Java第5章 初始化与清理 (笔记)
- think in java 笔记
- [Think in Java 笔记] Final关键字
- 读"Think in Java"后笔记(1)
- Think in java 笔记一(第1~2章)
- 【think in java 笔记1】java变量初始化顺序