Chapter 11: Collections of Objects a9 [Hello, Hello, Hello, World, World, }///:~ 你可以填满整个数组,或者像最后两句那样,只填其中的某个范围。相比 只能用一个值的 Arrays.fil(), Arrays2fi)的运行结果就更有趣 些了。 复制一个数组 Java标准类库提供了一个 System. arraycopy()的 static方法。相 比for循环,它能以更快的速度拷贝数组。 Systen. arraycopy()对 所有类型都作了重载。下面就是一个用它来处理int数组的例子 7/: c11: CopyingArrays java //Using System. arraycopy( import com. bruceeckel. simpletest *i import com. bruceeckel.util.* import java. util.* public class CopyingArrays t rivate static Test monitor new Test( public static void main(string[ args)t int[ i new int[7 Arrays. fill( fi11(j,99) System. out. println( 3="+ Arrays2 tostring (3)) System. arraycopy(i,0,3,0, ilength) Syst Syst 0, klength) System. out. println("k=+ Arrays2 tostring (k))i Arrays. fill(k, 10. System. arraycopy(, 0, i,0, klength)i System. out. println("i="+ Arrays2 tostring(i))i // objec Integer [10]i Integer[] v= new Integer[5]i Arrays. fill(u, new Integer(47))i fill (99)) System. out. println(" u =+ Arrays. aslist(u) System. out. println("V=+ Arrays. asList(v))i System. arraycopy(v, 0 length/2 ength) System. out. println(u ="+ Arrays. asList(u))i monitor. expect(new String[] t j=[99,99,99,99,99,99,99,99,99,991", =[47,47,47,47,47,47,47,99,99,99]", "k=[47,47,47,47,47]", 第16页共106页 www.wgqqh.com/shhgs/tij.html
Chapter 11: Collections of Objects 第 16 页 共 106 页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com "a9 = [Hello, Hello, Hello, World, World, Hello]" }); } } ///:~ 你可以填满整个数组,或者像最后两句那样,只填其中的某个范围。相比 只能用一个值的 Arrays.fill( ),Arrays2.fill( )的运行结果就更有趣 一些了。 复制一个数组 Java 标准类库提供了一个 System.arraycopy( )的 static 方法。相 比 for 循环,它能以更快的速度拷贝数组。System.arraycopy( )对 所有类型都作了重载。下面就是一个用它来处理 int 数组的例子。 //: c11:CopyingArrays.java // Using System.arraycopy( ) import com.bruceeckel.simpletest.*; import com.bruceeckel.util.*; import java.util.*; public class CopyingArrays { private static Test monitor = new Test( ); public static void main(String[] args) { int[] i = new int[7]; int[] j = new int[10]; Arrays.fill(i, 47); Arrays.fill(j, 99); System.out.println("i = " + Arrays2.toString(i)); System.out.println("j = " + Arrays2.toString(j)); System.arraycopy(i, 0, j, 0, i.length); System.out.println("j = " + Arrays2.toString(j)); int[] k = new int[5]; Arrays.fill(k, 103); System.arraycopy(i, 0, k, 0, k.length); System.out.println("k = " + Arrays2.toString(k)); Arrays.fill(k, 103); System.arraycopy(k, 0, i, 0, k.length); System.out.println("i = " + Arrays2.toString(i)); // Objects: Integer[] u = new Integer[10]; Integer[] v = new Integer[5]; Arrays.fill(u, new Integer(47)); Arrays.fill(v, new Integer(99)); System.out.println("u = " + Arrays.asList(u)); System.out.println("v = " + Arrays.asList(v)); System.arraycopy(v, 0, u, u.length/2, v.length); System.out.println("u = " + Arrays.asList(u)); monitor.expect(new String[] { "i = [47, 47, 47, 47, 47, 47, 47]", "j = [99, 99, 99, 99, 99, 99, 99, 99, 99, 99]", "j = [47, 47, 47, 47, 47, 47, 47, 99, 99, 99]", "k = [47, 47, 47, 47, 47]
Thinking in Java 3Edition "i=[103,103,103,103,103,47,47]", [47,47,47,47,47,47,47,47,47,47]" "v=[99,99,99,99,99]", 传给 arraycopy()的参数包括源数组,标识从源数组的哪个位置开始 拷贝的偏移量,目标数组,标识从目标数组的哪个位置开始拷贝的偏移 量,以及要拷贝的元素的数量。当然超出数组边界会引发异常。 这个例子告诉我们对象数组和 primitive数组都能拷贝。但是如果你拷贝 的是对象数组,那么你只拷贝了它们的 reference对象本身不会被 拷贝。这被称为浅拷贝(sha∥ ow copy)(见附录A)。 数组的比较 为了能比较数组是否完全相等, Arrays提供了经重载的 equals()方 法。当然,也是针对各种 primitive以及 object的。两个数组要想完全 相等,它们必须有相同数量的元素,而且数组的每个元素必须与另一个数 组的相对应的位置上的元素相等。元素的相等性,用 eqauls()判断。 对于 primitive,它会使用其 wrapper类的 equals():比如int使用 Integer equals()。)例如: //: c11: ComparingArrays java / Using Arrays. equals() import com. bruceeckel simpletest *i public class ComparingArrays private static Test monitor new Test( )i public static void main(string[] args) t int[ al=new int[10] int[ a2 new int [10]i Arrays. fill(al, 47)i fi11(a2,47) System. out. println(Arrays. equals(al, a2))i 2 System. out. println(Arrays. equals(al, a2))i String[] sl new string [5]i rrays fill(sl,"Hi")i String[] s2=t System. out. println(Arrays. equals (sl, s2))i monitor. expect(new String[] false", 第17页共106页 www.wgqqh.com/shhgs/tij.html
Thinking in Java 3rd Edition 第 17 页 共 106 页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com "i = [103, 103, 103, 103, 103, 47, 47]", "u = [47, 47, 47, 47, 47, 47, 47, 47, 47, 47]", "v = [99, 99, 99, 99, 99]", "u = [47, 47, 47, 47, 47, 99, 99, 99, 99, 99]" }); } } ///:~ 传给 arraycopy( )的参数包括源数组,标识从源数组的哪个位置开始 拷贝的偏移量,目标数组,标识从目标数组的哪个位置开始拷贝的偏移 量,以及要拷贝的元素的数量。当然超出数组边界会引发异常。 这个例子告诉我们对象数组和 primitive 数组都能拷贝。但是如果你拷贝 的是对象数组,那么你只拷贝了它们的 reference —— 对象本身不会被 拷贝。这被称为浅拷贝(shallow copy) (见附录 A)。 数组的比较 为了能比较数组是否完全相等,Arrays 提供了经重载的 equals( )方 法。当然,也是针对各种 primitive 以及 Object 的。两个数组要想完全 相等,它们必须有相同数量的元素,而且数组的每个元素必须与另一个数 组的相对应的位置上的元素相等。元素的相等性,用 eqauls( )判断。 (对于 primitive,它会使用其 wrapper 类的 equals( );比如 int 使用 Integer.equals( )。)例如: //: c11:ComparingArrays.java // Using Arrays.equals( ) import com.bruceeckel.simpletest.*; import java.util.*; public class ComparingArrays { private static Test monitor = new Test( ); public static void main(String[] args) { int[] a1 = new int[10]; int[] a2 = new int[10]; Arrays.fill(a1, 47); Arrays.fill(a2, 47); System.out.println(Arrays.equals(a1, a2)); a2[3] = 11; System.out.println(Arrays.equals(a1, a2)); String[] s1 = new String[5]; Arrays.fill(s1, "Hi"); String[] s2 = {"Hi", "Hi", "Hi", "Hi", "Hi"}; System.out.println(Arrays.equals(s1, s2)); monitor.expect(new String[] { "true", "false", "true" }); } } ///:~
Chapter 11: Collections of Objects 起先a1和a2是完全相等的,所以输出结果是“true”,但是我们修改 了一个元素,于是结果就变成“ false”了。在后一个例子里,s1的所有 元素指向相同的对象,但是s2却有五个各自独立的对象。但是数组是否 相等是基于其内容,(通过 Object equals()),因此结果仍是 " true 数组元素的比较 java1.0与1.1的类库缺少一些重要特性,其中之一就有没有提供算 法,甚至连个简单的排序都没有。对那些期望能有一个像样的标准类库的 人来说,这简直是太令人不解了。还好Java2作了补救,至少是解决了 排序问题。 编写泛型排序程序的时候会遇到一个问题,就是它只能根据对象的实际类 型进行比较。当然为每种类型都写一个的排序程序也不啻是一个办法,但 是这样一来你就会发现,碰到新的类型的时候,要想复用代码就不那么容 易了 设计的一项重要目标就是“要将会变和不会变的东西分开来”。这里,不 会变的东西就是通用的排序算法,而会变的东西就是对象是怎样比较大小 的。所以与其在各种排序程序里面都插进比较算法,还不如使用回调 ca∥back)技术。有了回调,你就能把“会根据情况的不同而改变”的代 码分离出来,而用相同的代码来调用那些会变的代码 java里面有两种能让你实现比较功能的方法。一是实现 java.lang Comparable接口,并以此实现类“自有的”比较方法。 这是一个很简单的接口,它只有一个方法 compareTo()。这个方法能 接受另一个对象作为参数,如果现有对象比参数小,它会返回一个负数 如果相同则返回零,如果现有的对象比参数大,它就返回一个正数 下面就是一个实现 Comparable接口的类,此外它还用Java标准类库 的 Arrays. sort()方法演示了比较的结果: //: c11: CompType java // Implementing Comparable in a class import com. bruceeckel. util.*i import java. util.*i public class CompType implements Comparable t Int 1 int 3 public CompType(int nl, int n2)I public string tostring( ) 第18页共106页 www.wgqqh.com/shhgs/tij.html emailshhgsasohu.com
Chapter 11: Collections of Objects 第 18 页 共 106 页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com 起先 a1 和 a2 是完全相等的,所以输出结果是“true”,但是我们修改 了一个元素,于是结果就变成“false”了。在后一个例子里,s1 的所有 元素指向相同的对象,但是 s2 却有五个各自独立的对象。但是数组是否 相等是基于其内容,(通过 Object.equals( )),因此结果仍是 "true"。 数组元素的比较 Java 1.0 与 1.1 的类库缺少一些重要特性,其中之一就有没有提供算 法,甚至连个简单的排序都没有。对那些期望能有一个像样的标准类库的 人来说,这简直是太令人不解了。还好 Java2 作了补救,至少是解决了 排序问题。 编写泛型排序程序的时候会遇到一个问题,就是它只能根据对象的实际类 型进行比较。当然为每种类型都写一个的排序程序也不啻是一个办法,但 是这样一来你就会发现,碰到新的类型的时候,要想复用代码就不那么容 易了。 设计的一项重要目标就是“要将会变和不会变的东西分开来”。这里,不 会变的东西就是通用的排序算法,而会变的东西就是对象是怎样比较大小 的。所以与其在各种排序程序里面都插进比较算法,还不如使用回调 (callback)技术。有了回调,你就能把“会根据情况的不同而改变”的代 码分离出来,而用相同的代码来调用那些会变的代码。 Java 里面有两种能让你实现比较功能的方法。一是实现 java.lang.Comparable 接口,并以此实现类“自有的”比较方法。 这是一个很简单的接口,它只有一个方法 compareTo( )。这个方法能 接受另一个对象作为参数,如果现有对象比参数小,它会返回一个负数, 如果相同则返回零,如果现有的对象比参数大,它就返回一个正数。 下面就是一个实现 Comparable 接口的类,此外它还用 Java 标准类库 的 Arrays.sort( )方法演示了比较的结果: //: c11:CompType.java // Implementing Comparable in a class. import com.bruceeckel.util.*; import java.util.*; public class CompType implements Comparable { int i; int j; public CompType(int n1, int n2) { i = n1; j = n2; } public String toString( ) {
return "i pu To(object rv) int rvi =(( CompType)rv).i 1:(主 private static rande ew Random() public static Generator generator( return new Generator()i public object next() return new CompType(r. nextInt(100),r. nextInt (100))i public static void main(st CompType[] CompType Arrays2. fill(a, generator( ) System. out. println( before sorting, a =" Arrays asList(a))i Arrays. sort(a) System. out. println( aslist(a)) }///:~ 旦你定义了比较的方法,你就得负责确定这个对象应该依据什么同其它 对象进行比较。这里我们只用到了i的值,而j的值则被忽略了。 static randint()方法会生成一个介于0到100之间的正数,而 generator()方法则用“创建匿名内部类”的方法(参见第八章),创建 了一个实现 Generator接口的对象。而这个对象又会用 randInt()生 成的随机数创建了多个 CompType对象。main()用这个 generator 把compτype型的数组填满。接下来,开始对数组排序。如果 CompType没有实现 Comparable接口,那么程序运行调用到 sort()会把传给它的参数转换成 Comparable otion错误。这是因为 现在假设,有人给你一个没有实现 Comparable接口的类,或者这个 类实现了 Comparable接口,但是你发现它的工作方式不是你所希望 的,于是要重新定义一个新的比较方法。Java没有强求你一定要把比较 代码塞进类里,它的解决方案是使用“策略模式( strategy design pattern)”。有了策略之后,你就能把会变的代码封装到它自己的类里 (即所谓的策略对象 strategy object)。你把策略对象交给不会变的代 码,然后由它运用策略完成整个算法。这样,你就可以用不同的策略对象 来表示不同的比较方式,然后把它们都交给同一个排序程序了。接下来就 要“通过实现 Comparator接口”来定义策略对象了。这个接口有两个 4 Design Patterns, rich gamma等著, Addison- .Wesley1995年出版。 第19页共106页 www.wgqqh.com/shhgs/tij.html
Thinking in Java 3rd Edition 第 19 页 共 106 页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com return "[i = " + i + ", j = " + j + "]"; } public int compareTo(Object rv) { int rvi = ((CompType)rv).i; return (i < rvi ? -1 : (i == rvi ? 0 : 1)); } private static Random r = new Random( ); public static Generator generator( ) { return new Generator( ) { public Object next( ) { return new CompType(r.nextInt(100),r.nextInt(100)); } }; } public static void main(String[] args) { CompType[] a = new CompType[10]; Arrays2.fill(a, generator( )); System.out.println( "before sorting, a = " + Arrays.asList(a)); Arrays.sort(a); System.out.println( "after sorting, a = " + Arrays.asList(a)); } } ///:~ 一旦你定义了比较的方法,你就得负责确定这个对象应该依据什么同其它 对象进行比较。这里我们只用到了 i 的值,而 j 的值则被忽略了。 static randInt( )方法会生成一个介于 0 到 100 之间的正数,而 generator( )方法则用“创建匿名内部类”的方法(参见第八章),创建 了一个实现 Generator 接口的对象。而这个对象又会用 randInt( )生 成的随机数创建了多个 CompType 对象。main( )用这个 generator 把 CompType 型的数组填满。接下来,开始对数组排序。如果 CompType 没有实现 Comparable 接口,那么程序运行调用到 sort( )的时候,就会引发一个 ClassCastException 错误。这是因为 sort( )会把传给它的参数转换成 Comparable。 现在假设,有人给你一个没有实现 Comparable 接口的类,或者这个 类实现了 Comparable 接口,但是你发现它的工作方式不是你所希望 的,于是要重新定义一个新的比较方法。Java 没有强求你一定要把比较 代码塞进类里,它的解决方案是使用“策略模式(strategy design pattern)4”。有了策略之后,你就能把会变的代码封装到它自己的类里 (即所谓的策略对象 strategy object)。你把策略对象交给不会变的代 码,然后由它运用策略完成整个算法。这样,你就可以用不同的策略对象 来表示不同的比较方式,然后把它们都交给同一个排序程序了。接下来就 要“通过实现 Comparator 接口”来定义策略对象了。这个接口有两个 4 Design Patterns, Erich Gamma 等著, Addison-Wesley 1995 年出版
Chapter 11: Collections of Objects 方法 compare()和 equals()。但是除非是有特殊的性能要求,否则 你用不着去实现 equals()。因为只要是类,它就都隐含地继承自 Object,而 Object里面已经有了一个 equals()了。所以你尽可以使 用缺省的 Object的 equals〔),这样就已经满足接口的要求了。 (我们要等一会儿才会讲到的) Collections类里专门有一个会返回与对 象自有的比较法相反的 Comparator的方法。它能很轻易地被用到 mpType上面 //: cll: Reverse. java / The Collecions reverseorder()Comparator import com. bruceeckel. util.*i import java.util.*i public class Reverse i CompType [] a= new CompType [10/ gs)( public static void main (String[] args) t Arrays2. fill(a, CompType generator( ) before sorting Arrays aslist(a)) Arrays. sort(a, Collections. reverseOrder())i System. out. println( " after sorting, a = Arrays asList(a))i }// Collections. reverseorder()返回了一个 Comparator的 再举个例子,我们让 Comparator根据j,而不是i的值来比较 CompType对象 Implementing a Comparator for a class import com. bruceeckel.util.*i import java.util.* class CompTypeComparator implements Comparator t public int compare (object ol, object o2)i int j2 =((CompType)o2).] return (31 <32?-1:(01==12? 1)); public static void main(String[] args)i CompType[] a=new CompType [101 Arrays2. fill(a, CompType generator( ))i Syst before sorting, a = Arrays aslist(a))i Arrays. sort(a, new CompType Comparator())i System. out. println( 第20页共106页 www.wgqqh.com/shhgs/tij.html
Chapter 11: Collections of Objects 第 20 页 共 106 页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com 方法 compare( )和 equals( )。但是除非是有特殊的性能要求,否则 你用不着去实现 equals( )。因为只要是类,它就都隐含地继承自 Object,而 Object 里面已经有了一个 equals( )了。所以你尽可以使 用缺省的 Object 的 equals( ),这样就已经满足接口的要求了。 (我们要等一会儿才会讲到的)Collections 类里专门有一个会返回与对 象自有的比较法相反的 Comparator 的方法。它能很轻易地被用到 CompType 上面。 //: c11:Reverse.java // The Collecions.reverseOrder( ) Comparator import com.bruceeckel.util.*; import java.util.*; public class Reverse { public static void main(String[] args) { CompType[] a = new CompType[10]; Arrays2.fill(a, CompType.generator( )); System.out.println( "before sorting, a = " + Arrays.asList(a)); Arrays.sort(a, Collections.reverseOrder( )); System.out.println( "after sorting, a = " + Arrays.asList(a)); } } ///:~ Collections.reverseOrder( )返回了一个 Comparator 的 reference。 再举个例子,我们让 Comparator 根据 j,而不是 i 的值来比较 CompType 对象。 //: c11:ComparatorTest.java // Implementing a Comparator for a class. import com.bruceeckel.util.*; import java.util.*; class CompTypeComparator implements Comparator { public int compare(Object o1, Object o2) { int j1 = ((CompType)o1).j; int j2 = ((CompType)o2).j; return (j1 < j2 ? -1 : (j1 == j2 ? 0 : 1)); } } public class ComparatorTest { public static void main(String[] args) { CompType[] a = new CompType[10]; Arrays2.fill(a, CompType.generator( )); System.out.println( "before sorting, a = " + Arrays.asList(a)); Arrays.sort(a, new CompTypeComparator( )); System.out.println(