數組:能夠建立並組裝它們,經過使用整型索引值訪問它們的元素,而且它們的尺寸不能改變。java
數組與其餘種類的容器之間的區別有三方面:效率,類型和保存基本類型的能力。
數組是一種效率最高的存儲和隨機訪問對象引用序列的方式。數組就是一個簡單的線性序列,這使得元素訪問很是快速。可是爲這種速度所付出的代價是數組對象的大小固定,而且在其生命週期中不可改變。
ArrayList:它能夠經過一個新實例,而後把舊實例中全部引用移到新實例中,從而實現更多空間的自動分配。但它的效率比數組低不少。
數組能夠持有基本類型,而泛型以前的容器不能。但有了泛型,容器舊能夠指定並檢查它們所持有對象的類型,而且有了自動包裝機制,容器看起來還可以持有基本類型。
數組和泛型容器比較:算法
import java.util.*; import static net.mindview.util.Print.*; class BerylliumSphere { private static long counter; private final long id = counter++; public String toString() { return "Sphere " + id; } } public class ContainerComparison { public static void main(String[] args) { BerylliumSphere[] spheres = new BerylliumSphere[10]; for(int i = 0; i < 5; i++) spheres[i] = new BerylliumSphere(); print(Arrays.toString(spheres)); print(spheres[4]); List<BerylliumSphere> sphereList = new ArrayList<BerylliumSphere>(); for(int i = 0; i < 5; i++) sphereList.add(new BerylliumSphere()); print(sphereList); print(sphereList.get(4)); int[] integers = { 0, 1, 2, 3, 4, 5 }; print(Arrays.toString(integers)); print(integers[4]); List<Integer> intList = new ArrayList<Integer>( Arrays.asList(0, 1, 2, 3, 4, 5)); intList.add(97); print(intList); print(intList.get(4)); } } /* Output: [Sphere 0, Sphere 1, Sphere 2, Sphere 3, Sphere 4, null, null, null, null, null] Sphere 4 [Sphere 5, Sphere 6, Sphere 7, Sphere 8, Sphere 9] Sphere 9 [0, 1, 2, 3, 4, 5] 4 [0, 1, 2, 3, 4, 5, 97] 4 *///:~
數組的優勢是效率。設計模式
不管使用哪一種類型的數組,數組標識符其實只是一個引用,指向在堆中建立的一個真實對象,這個對象用以保存指向其餘對象的引用。
對象數組和基本類型數組在使用上幾乎是相同的。惟一區別就是對象數組保存的是引用,基本類型數組直接保存基本類型的值。數組
import java.util.*; import static net.mindview.util.Print.*; public class ArrayOptions { public static void main(String[] args) { // Arrays of objects: BerylliumSphere[] a; // Local uninitialized variable BerylliumSphere[] b = new BerylliumSphere[5]; // The references inside the array are // automatically initialized to null: print("b: " + Arrays.toString(b)); BerylliumSphere[] c = new BerylliumSphere[4]; for(int i = 0; i < c.length; i++) if(c[i] == null) // Can test for null reference c[i] = new BerylliumSphere(); // Aggregate initialization: BerylliumSphere[] d = { new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere() }; print("d"+Arrays.toString(d)); // Dynamic aggregate initialization: a = new BerylliumSphere[]{ new BerylliumSphere(), new BerylliumSphere(), }; // (Trailing comma is optional in both cases) print("a.length = " + a.length); print("b.length = " + b.length); print("c.length = " + c.length); print("d.length = " + d.length); a = d; print("a.length = " + a.length); // Arrays of primitives: int[] e; // Null reference int[] f = new int[5]; // The primitives inside the array are // automatically initialized to zero: print("f: " + Arrays.toString(f)); int[] g = new int[4]; for(int i = 0; i < g.length; i++) g[i] = i*i; int[] h = { 11, 47, 93 }; // Compile error: variable e not initialized: //!print("e.length = " + e.length); print("f.length = " + f.length); print("g.length = " + g.length); print("h.length = " + h.length); e = h; print("e.length = " + e.length); e = new int[]{ 1, 2 }; print("e.length = " + e.length); } } /* Output: b: [null, null, null, null, null] a.length = 2 b.length = 5 c.length = 4 d.length = 3 a.length = 3 f: [0, 0, 0, 0, 0] f.length = 5 g.length = 4 h.length = 3 e.length = 3 e.length = 2 *///:~
數組的清理由垃圾回收機制負責。安全
import java.util.*; public class IceCream { private static Random rand = new Random(47); static final String[] FLAVORS = { "Chocolate", "Strawberry", "Vanilla Fudge Swirl", "Mint Chip", "Mocha Almond Fudge", "Rum Raisin", "Praline Cream", "Mud Pie" }; public static String[] flavorSet(int n) { if(n > FLAVORS.length) throw new IllegalArgumentException("Set too big"); String[] results = new String[n]; boolean[] picked = new boolean[FLAVORS.length]; for(int i = 0; i < n; i++) { int t; do t = rand.nextInt(FLAVORS.length); while(picked[t]); results[i] = FLAVORS[t]; picked[t] = true; } return results; } public static void main(String[] args) { for(int i = 0; i < 7; i++) System.out.println(Arrays.toString(flavorSet(3))); } } /* Output: [Rum Raisin, Mint Chip, Mocha Almond Fudge] [Chocolate, Strawberry, Mocha Almond Fudge] [Strawberry, Mint Chip, Mocha Almond Fudge] [Rum Raisin, Vanilla Fudge Swirl, Mud Pie] [Vanilla Fudge Swirl, Chocolate, Mocha Almond Fudge] [Praline Cream, Strawberry, Mocha Almond Fudge] [Mocha Almond Fudge, Strawberry, Mint Chip] *///:~
對於基本類型得多維數組,能夠經過使用花括號將每一個向量隔開:app
import java.util.*; public class MultidimensionalPrimitiveArray { public static void main(String[] args) { int[][] a = { { 1, 2, 3, }, { 4, 5, 6, }, };System.out.println(Arrays.deepToString(a)); System.out.println(a[0].length); System.out.println(a[1].length); } } /* Output: [[1, 2, 3], [4, 5, 6]] *///:~
還可使用new來分配數組:dom
import java.util.*; public class ThreeDWithNew { public static void main(String[] args) { // 3-D array with fixed length: int[][][] a = new int[2][2][4]; System.out.println(Arrays.deepToString(a)); } } /* Output: [[[0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]] *///:~
你能夠看到基本類型數組得值在不進行顯式初始化得狀況下,會被自動初始化。對象數組會被初始化爲null。
數組中構成矩陣得每一個向量均可以具備任意得長度(粗糙數組)ide
import java.util.*; public class RaggedArray { public static void main(String[] args) { Random rand = new Random(47); // 3-D array with varied-length vectors: int[][][] a = new int[rand.nextInt(7)][][]; for(int i = 0; i < a.length; i++) { a[i] = new int[rand.nextInt(5)][]; for(int j = 0; j < a[i].length; j++) a[i][j] = new int[rand.nextInt(5)]; } System.out.println(Arrays.deepToString(a)); } } /* Output: [[], [[0], [0], [0, 0, 0, 0]], [[], [0, 0], [0, 0]], [[0, 0, 0], [0], [0, 0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0], []], [[0], [], [0]]] *///:~
用花括號把多個new表達式組織到一塊兒:工具
import java.util.*; public class MultidimensionalObjectArrays { public static void main(String[] args) { BerylliumSphere[][] spheres = { { new BerylliumSphere(), new BerylliumSphere() }, { new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere() }, { new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere() }, }; System.out.println(Arrays.deepToString(spheres)); } } /* Output: [[Sphere 0, Sphere 1], [Sphere 2, Sphere 3, Sphere 4, Sphere 5], [Sphere 6, Sphere 7, Sphere 8, Sphere 9, Sphere 10, Sphere 11, Sphere 12, Sphere 13]] *///:~
自動包裝機制對數組初始化器也起做用:oop
import java.util.*; public class AutoboxingArrays { public static void main(String[] args) { Integer[][] a = { // Autoboxing: { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, { 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 }, { 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 }, }; System.out.println(Arrays.deepToString(a)); } } /* Output: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [21, 22, 23, 24, 25, 26, 27, 28, 29, 30], [51, 52, 53, 54, 55, 56, 57, 58, 59, 60], [71, 72, 73, 74, 75, 76, 77, 78, 79, 80]] *///:~
Arrays.deepToString()方法對基本類型數組和對象數組都起做用:
import java.util.*; public class MultiDimWrapperArray { public static void main(String[] args) { Integer[][] a1 = { // Autoboxing { 1, 2, 3, }, { 4, 5, 6, }, }; Double[][][] a2 = { // Autoboxing { { 1.1, 2.2 }, { 3.3, 4.4 } }, { { 5.5, 6.6 }, { 7.7, 8.8 } }, { { 9.9, 1.2 }, { 2.3, 3.4 } }, }; String[][] a3 = { { "The", "Quick", "Sly", "Fox" }, { "Jumped", "Over" }, { "The", "Lazy", "Brown", "Dog", "and", "friend" }, }; String[][] a4=new String[2][3]; System.out.println("a1: " + Arrays.deepToString(a1)); System.out.println("a2: " + Arrays.deepToString(a2)); System.out.println("a3: " + Arrays.deepToString(a3)); System.out.println("a3: " + Arrays.deepToString(a4)); } } /* Output: a1: [[1, 2, 3], [4, 5, 6]] a2: [[[1.1, 2.2], [3.3, 4.4]], [[5.5, 6.6], [7.7, 8.8]], [[9.9, 1.2], [2.3, 3.4]]] a3: [[The, Quick, Sly, Fox], [Jumped, Over], [The, Lazy, Brown, Dog, and, friend]] *///:~
數組與泛型不能很好的結合。你不能實例化具備參數化類型的數組。
擦除會移除參數類型信息,而數組必須知道它們所持有的確切類型,以強制保證類型安全。
參數化數組自己的類型:
class ClassParameter<T> { public T[] f(T[] arg) { return arg; } } class MethodParameter { public static <T> T[] f(T[] arg) { return arg; } } public class ParameterizedArrayType { public static void main(String[] args) { Integer[] ints = { 1, 2, 3, 4, 5 }; Double[] doubles = { 1.1, 2.2, 3.3, 4.4, 5.5 }; Integer[] ints2 = new ClassParameter<Integer>().f(ints); Double[] doubles2 = new ClassParameter<Double>().f(doubles); ints2 = MethodParameter.f(ints); doubles2 = MethodParameter.f(doubles); } } ///:~
不能建立實際的持有泛型的數組對象,可是你能夠建立非泛型的數組,而後將其轉型:
import java.util.*; public class ArrayOfGenerics { @SuppressWarnings("unchecked") public static void main(String[] args) { List<String>[] ls; List[] la = new List[10]; ls = (List<String>[])la; // "Unchecked" warning ls[0] = new ArrayList<String>(); // Compile-time checking produces an error: //ls[1] = new ArrayList<Integer>(); // The problem: List<String> is a subtype of Object Object[] objects = ls; // So assignment is OK // Compiles and runs without complaint: objects[1] = new ArrayList<Integer>(); // However, if your needs are straightforward it is // possible to create an array of generics, albeit // with an "unchecked" warning: List<BerylliumSphere>[] spheres = (List<BerylliumSphere>[])new List[10]; for(int i = 0; i < spheres.length; i++) spheres[i] = new ArrayList<BerylliumSphere>(); } } ///:~
泛型在類或方法的邊界處頗有效,而在類或方法的內部,擦除一般會使泛型變得不適用。
不能建立泛型數組:
public class ArrayOfGenericType<T> { T[] array; // OK @SuppressWarnings("unchecked") public ArrayOfGenericType(int size) { //! array = new T[size]; // Illegal array = (T[])new Object[size]; // "unchecked" Warning } // Illegal: //! public <U> U[] makeArray() { return new U[10]; } } ///:~
只能用一個值填充各個位置,而針對對象而言,就是複製同一個引用進行填充:
import java.util.*; import static net.mindview.util.Print.*; public class FillingArrays { public static void main(String[] args) { int size = 6; boolean[] a1 = new boolean[size]; byte[] a2 = new byte[size]; char[] a3 = new char[size]; short[] a4 = new short[size]; int[] a5 = new int[size]; long[] a6 = new long[size]; float[] a7 = new float[size]; double[] a8 = new double[size]; String[] a9 = new String[size]; Arrays.fill(a1, true); print("a1 = " + Arrays.toString(a1)); Arrays.fill(a2, (byte)11); print("a2 = " + Arrays.toString(a2)); Arrays.fill(a3, 'x'); print("a3 = " + Arrays.toString(a3)); Arrays.fill(a4, (short)17); print("a4 = " + Arrays.toString(a4)); Arrays.fill(a5, 19); print("a5 = " + Arrays.toString(a5)); Arrays.fill(a6, 23); print("a6 = " + Arrays.toString(a6)); Arrays.fill(a7, 29); print("a7 = " + Arrays.toString(a7)); Arrays.fill(a8, 47); print("a8 = " + Arrays.toString(a8)); Arrays.fill(a9, "Hello"); print("a9 = " + Arrays.toString(a9)); // Manipulating ranges: Arrays.fill(a9, 3, 5, "World"); print("a9 = " + Arrays.toString(a9)); } } /* Output: a1 = [true, true, true, true, true, true] a2 = [11, 11, 11, 11, 11, 11] a3 = [x, x, x, x, x, x] a4 = [17, 17, 17, 17, 17, 17] a5 = [19, 19, 19, 19, 19, 19] a6 = [23, 23, 23, 23, 23, 23] a7 = [29.0, 29.0, 29.0, 29.0, 29.0, 29.0] a8 = [47.0, 47.0, 47.0, 47.0, 47.0, 47.0] a9 = [Hello, Hello, Hello, Hello, Hello, Hello] a9 = [Hello, Hello, Hello, World, World, Hello] *///:~
使用Arrays.fill()能夠填充整個數組,或者只填充某個區域。
package net.mindview.util; public class CountingGenerator { static char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); public CountingGenerator() { } public static class Boolean implements Generator<java.lang.Boolean> { private boolean value = false; public Boolean() { } public java.lang.Boolean next() { this.value = !this.value; return this.value; } } public static class Byte implements Generator<java.lang.Byte> { private byte value = 0; public Byte() { } public java.lang.Byte next() { return this.value++; } } public static class Character implements Generator<java.lang.Character> { int index = -1; public Character() { } public java.lang.Character next() { this.index = (this.index + 1) % CountingGenerator.chars.length; return CountingGenerator.chars[this.index]; } } public static class Double implements Generator<java.lang.Double> { private double value = 0.0D; public Double() { } public java.lang.Double next() { double result = (double)(this.value++); return result; } } public static class Float implements Generator<java.lang.Float> { private float value = 0.0F; public Float() { } public java.lang.Float next() { float result = this.value; this.value = (float)((double)this.value + 1.0D); return result; } } public static class Integer implements Generator<java.lang.Integer> { private int value = 0; public Integer() { } public java.lang.Integer next() { return this.value++; } } public static class Long implements Generator<java.lang.Long> { private long value = 0L; public Long() { } public java.lang.Long next() { return java.lang.Long.valueOf((long)(this.value++)); } } public static class Short implements Generator<java.lang.Short> { private short value = 0; public Short() { } public java.lang.Short next() { return this.value++; } } public static class String implements Generator<java.lang.String> { private int length = 7; Generator<java.lang.Character> cg = new CountingGenerator.Character(); public String() { } public String(int length) { this.length = length; } public java.lang.String next() { char[] buf = new char[this.length]; for(int i = 0; i < this.length; ++i) { buf[i] = ((java.lang.Character)this.cg.next()).charValue(); } return new java.lang.String(buf); } } }
經過反射使用這個工具:
import net.mindview.util.*; public class GeneratorsTest { public static int size = 10; public static void test(Class<?> surroundingClass) { for(Class<?> type : surroundingClass.getClasses()) { System.out.print(type.getSimpleName() + ": "); try { Generator<?> g = (Generator<?>)type.newInstance(); for(int i = 0; i < size; i++) System.out.printf(g.next() + " "); System.out.println(); } catch(Exception e) { throw new RuntimeException(e); } } } public static void main(String[] args) { test(CountingGenerator.class); } } /* Output: Double: 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 Float: 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 Long: 0 1 2 3 4 5 6 7 8 9 Integer: 0 1 2 3 4 5 6 7 8 9 Short: 0 1 2 3 4 5 6 7 8 9 String: abcdefg hijklmn opqrstu vwxyzAB CDEFGHI JKLMNOP QRSTUVW XYZabcd efghijk lmnopqr Character: a b c d e f g h i j Byte: 0 1 2 3 4 5 6 7 8 9 Boolean: true false true false true false true false true false *///:~
使用隨機數生成器的Generator:
package net.mindview.util; import java.util.Random; public class RandomGenerator { private static Random r = new Random(47L); public RandomGenerator() { } public static class Boolean implements Generator<java.lang.Boolean> { public Boolean() { } public java.lang.Boolean next() { return RandomGenerator.r.nextBoolean(); } } public static class Byte implements Generator<java.lang.Byte> { public Byte() { } public java.lang.Byte next() { return (byte)RandomGenerator.r.nextInt(); } } public static class Character implements Generator<java.lang.Character> { public Character() { } public java.lang.Character next() { return CountingGenerator.chars[RandomGenerator.r.nextInt(CountingGenerator.chars.length)]; } } public static class Double implements Generator<java.lang.Double> { public Double() { } public java.lang.Double next() { long trimmed = Math.round(RandomGenerator.r.nextDouble() * 100.0D); return (double)trimmed / 100.0D; } } public static class Float implements Generator<java.lang.Float> { public Float() { } public java.lang.Float next() { int trimmed = Math.round(RandomGenerator.r.nextFloat() * 100.0F); return (float)trimmed / 100.0F; } } public static class Integer implements Generator<java.lang.Integer> { private int mod = 10000; public Integer() { } public Integer(int modulo) { this.mod = modulo; } public java.lang.Integer next() { return RandomGenerator.r.nextInt(this.mod); } } public static class Long implements Generator<java.lang.Long> { private int mod = 10000; public Long() { } public Long(int modulo) { this.mod = modulo; } public java.lang.Long next() { return new java.lang.Long((long)RandomGenerator.r.nextInt(this.mod)); } } public static class Short implements Generator<java.lang.Short> { public Short() { } public java.lang.Short next() { return (short)RandomGenerator.r.nextInt(); } } public static class String extends net.mindview.util.CountingGenerator.String { public String() { this.cg = new RandomGenerator.Character(); } public String(int length) { super(length); this.cg = new RandomGenerator.Character(); } } }
這個工具只能產生Object子類型數組,而不能產生基本類型數組:
package net.mindview.util; import java.lang.reflect.Array; public class Generated { public Generated() { } public static <T> T[] array(T[] a, Generator<T> gen) { return (new CollectionData(gen, a.length)).toArray(a); } public static <T> T[] array(Class<T> type, Generator<T> gen, int size) { Object[] a = (Object[])Array.newInstance(type, size); return (new CollectionData(gen, size)).toArray(a); } }
使用反射動態建立具備恰當類型和數量的新數組,而後使用與第一個方法相同的技術來填充該數組:
import java.util.*; import net.mindview.util.*; public class TestGenerated { public static void main(String[] args) { Integer[] a = { 9, 8, 7, 6 }; System.out.println(Arrays.toString(a)); a = Generated.array(a,new CountingGenerator.Integer()); System.out.println(Arrays.toString(a)); Integer[] b = Generated.array(Integer.class, new CountingGenerator.Integer(), 15); System.out.println(Arrays.toString(b)); } } /* Output: [9, 8, 7, 6] [0, 1, 2, 3] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] *///:~
泛型不能用於基本類型,能夠用生成器來填充基本類型。
建立一個轉換器,它能夠接受任意的包裝器對象數組,並將其轉化爲相應的基本類型數組:
package net.mindview.util; public class ConvertTo { public ConvertTo() { } public static boolean[] primitive(Boolean[] in) { boolean[] result = new boolean[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].booleanValue(); } return result; } public static char[] primitive(Character[] in) { char[] result = new char[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].charValue(); } return result; } public static byte[] primitive(Byte[] in) { byte[] result = new byte[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].byteValue(); } return result; } public static short[] primitive(Short[] in) { short[] result = new short[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].shortValue(); } return result; } public static int[] primitive(Integer[] in) { int[] result = new int[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].intValue(); } return result; } public static long[] primitive(Long[] in) { long[] result = new long[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].longValue(); } return result; } public static float[] primitive(Float[] in) { float[] result = new float[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].floatValue(); } return result; } public static double[] primitive(Double[] in) { double[] result = new double[in.length]; for(int i = 0; i < in.length; ++i) { result[i] = in[i].doubleValue(); } return result; } }
Arrays類有一套用於static實用方法,它有六個基本方法:equals()比較數組,deepEquals()比較多維數組;fill()填充;sort()用於對數組排序;binarySearch()用於在排序的數組中查找元素;toString()產生數組的String表示;hashCode()產生數組的散列碼。
System.arraycopy()它複製數組比for快:
import java.util.*; import static net.mindview.util.Print.*; public class CopyingArrays { public static void main(String[] args) { int[] i = new int[7]; int[] j = new int[10]; Arrays.fill(i, 47); Arrays.fill(j, 99); print("i = " + Arrays.toString(i)); print("j = " + Arrays.toString(j)); System.arraycopy(i, 0, j, 0, i.length); print("j = " + Arrays.toString(j)); int[] k = new int[5]; Arrays.fill(k, 103); System.arraycopy(i, 0, k, 0, k.length); print("k = " + Arrays.toString(k)); Arrays.fill(k, 103); System.arraycopy(k, 0, i, 0, k.length); print("i = " + Arrays.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)); print("u = " + Arrays.toString(u)); print("v = " + Arrays.toString(v)); System.arraycopy(v, 0, u, u.length/2, v.length); print("u = " + Arrays.toString(u)); } } /* Output: 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] 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] *///:~
System.arraycopy()不會執行自動包裝,兩個數組必須具備相同的確切類型。
import java.util.*; import static net.mindview.util.Print.*; public class ComparingArrays { public static void main(String[] args) { int[] a1 = new int[10]; int[] a2 = new int[10]; Arrays.fill(a1, 47); Arrays.fill(a2, 47); print(Arrays.equals(a1, a2)); a2[3] = 11; print(Arrays.equals(a1, a2)); String[] s1 = new String[4]; Arrays.fill(s1, "Hi"); String[] s2 = { new String("Hi"), new String("Hi"), new String("Hi"), new String("Hi") }; print(Arrays.equals(s1, s2)); } } /* Output: true false true *///:~
排序必須根據對象的實際類型執行比較操做。
程序設計的基本目標是:將保存不變的事物與會發生改變的事物相分離。這裏,不變的是通用的排序算法,變化的是各類對象相互比較的方式。經過使用策略設計模式,能夠將會發生變化的代碼封裝在單獨的類中(策略對象),你能夠將策略對象傳遞給老是相同的代碼。
一種比較實現Comparable接口:
import java.util.*; import net.mindview.util.*; import static net.mindview.util.Print.*; public class CompType implements Comparable<CompType> { int i; int j; private static int count = 1; public CompType(int n1, int n2) { i = n1; j = n2; } public String toString() { String result = "[i = " + i + ", j = " + j + "]"; if(count++ % 3 == 0) result += "\n"; return result; } public int compareTo(CompType rv) { return (i < rv.i ? -1 : (i == rv.i ? 0 : 1)); } private static Random r = new Random(47); public static Generator<CompType> generator() { return new Generator<CompType>() { public CompType next() { return new CompType(r.nextInt(100),r.nextInt(100)); } }; } public static void main(String[] args) { CompType[] a = Generated.array(new CompType[12], generator()); print("before sorting:"); print(Arrays.toString(a)); Arrays.sort(a); print("after sorting:"); print(Arrays.toString(a)); } } /* Output: before sorting: [[i = 58, j = 55], [i = 93, j = 61], [i = 61, j = 29] , [i = 68, j = 0], [i = 22, j = 7], [i = 88, j = 28] , [i = 51, j = 89], [i = 9, j = 78], [i = 98, j = 61] , [i = 20, j = 58], [i = 16, j = 40], [i = 11, j = 22] ] after sorting: [[i = 9, j = 78], [i = 11, j = 22], [i = 16, j = 40] , [i = 20, j = 58], [i = 22, j = 7], [i = 51, j = 89] , [i = 58, j = 55], [i = 61, j = 29], [i = 68, j = 0] , [i = 88, j = 28], [i = 93, j = 61], [i = 98, j = 61] ] *///:~
另外一種方法,Collection類包含一個reverseOrder()fangfa,該方法能夠產生一個Comparator,它能夠反轉天然排序順序:
import java.util.*; import net.mindview.util.*; import static net.mindview.util.Print.*; public class Reverse { public static void main(String[] args) { CompType[] a = Generated.array( new CompType[12], CompType.generator()); print("before sorting:"); print(Arrays.toString(a)); Arrays.sort(a, Collections.reverseOrder()); print("after sorting:"); print(Arrays.toString(a)); } } /* Output: before sorting: [[i = 58, j = 55], [i = 93, j = 61], [i = 61, j = 29] , [i = 68, j = 0], [i = 22, j = 7], [i = 88, j = 28] , [i = 51, j = 89], [i = 9, j = 78], [i = 98, j = 61] , [i = 20, j = 58], [i = 16, j = 40], [i = 11, j = 22] ] after sorting: [[i = 98, j = 61], [i = 93, j = 61], [i = 88, j = 28] , [i = 68, j = 0], [i = 61, j = 29], [i = 58, j = 55] , [i = 51, j = 89], [i = 22, j = 7], [i = 20, j = 58] , [i = 16, j = 40], [i = 11, j = 22], [i = 9, j = 78] ] *///:~
也能夠本身編寫Comparator:
import java.util.*; import net.mindview.util.*; import static net.mindview.util.Print.*; class CompTypeComparator implements Comparator<CompType> { public int compare(CompType o1, CompType o2) { return (o1.j < o2.j ? -1 : (o1.j == o2.j ? 0 : 1)); } } public class ComparatorTest { public static void main(String[] args) { CompType[] a = Generated.array( new CompType[12], CompType.generator()); print("before sorting:"); print(Arrays.toString(a)); Arrays.sort(a, new CompTypeComparator()); print("after sorting:"); print(Arrays.toString(a)); } } /* Output: before sorting: [[i = 58, j = 55], [i = 93, j = 61], [i = 61, j = 29] , [i = 68, j = 0], [i = 22, j = 7], [i = 88, j = 28] , [i = 51, j = 89], [i = 9, j = 78], [i = 98, j = 61] , [i = 20, j = 58], [i = 16, j = 40], [i = 11, j = 22] ] after sorting: [[i = 68, j = 0], [i = 22, j = 7], [i = 11, j = 22] , [i = 88, j = 28], [i = 61, j = 29], [i = 16, j = 40] , [i = 58, j = 55], [i = 20, j = 58], [i = 93, j = 61] , [i = 98, j = 61], [i = 9, j = 78], [i = 51, j = 89] ] *///:~
使用內置的排序方法,就能夠對任意的基本類型數組排序,也能夠對任意的對象數組進行排序,只要該對象實現了Comparable接口或具備關聯的Comparator。
隨機生成String對象,並排序:
import java.util.*; import net.mindview.util.*; import static net.mindview.util.Print.*; public class StringSorting { public static void main(String[] args) { String[] sa = Generated.array(new String[20], new RandomGenerator.String(5)); print("Before sort: " + Arrays.toString(sa)); Arrays.sort(sa); print("After sort: " + Arrays.toString(sa)); Arrays.sort(sa, Collections.reverseOrder()); print("Reverse sort: " + Arrays.toString(sa)); Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER); print("Case-insensitive sort: " + Arrays.toString(sa)); } }
排序算法針對正排序的特殊類型進行了優化——針對基本類型設計的"快速排序",以及針對對象設計的"穩定歸併排序"。
import java.util.*; import net.mindview.util.*; import static net.mindview.util.Print.*; public class ArraySearching { public static void main(String[] args) { Generator<Integer> gen = new RandomGenerator.Integer(1000); int[] a = ConvertTo.primitive( Generated.array(new Integer[25], gen)); Arrays.sort(a); print("Sorted array: " + Arrays.toString(a)); while(true) { int r = gen.next(); int location = Arrays.binarySearch(a, r); if(location >= 0) { print("Location of " + r + " is " + location + ", a[" + location + "] = " + a[location]); break; // Out of while loop } } } }
若是使用Comparator排序某個對象數組,在使用binarySearch()時必須提供一樣的Comparator。
import java.util.*; import net.mindview.util.*; public class AlphabeticSearch { public static void main(String[] args) { String[] sa = Generated.array(new String[30], new RandomGenerator.String(5)); Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER); System.out.println(Arrays.toString(sa)); int index = Arrays.binarySearch(sa, sa[10], String.CASE_INSENSITIVE_ORDER); System.out.println("Index: "+ index + "\n"+ sa[index]); } } /* Output: [bkIna, cQrGs, cXZJo, dLsmw, eGZMm, EqUCB, gwsqP, hKcxr, HLGEa, HqXum, HxxHv, JMRoE, JmzMs, Mesbt, MNvqe, nyGcF, ogoYW, OneOE, OWZnT, RFJQA, rUkZP, sgqia, slJrL, suEcU, uTpnX, vpfFv, WHkjU, xxEAJ, YNzbr, zDyCy] Index: 10 HxxHv *///:~