Java基礎之十六 數組

數組:能夠建立並組裝它們,經過使用整型索引值訪問它們的元素,而且它們的尺寸不能改變。java

16.1 數組爲何特殊

數組與其餘種類的容器之間的區別有三方面:效率,類型和保存基本類型的能力。
數組是一種效率最高的存儲和隨機訪問對象引用序列的方式。數組就是一個簡單的線性序列,這使得元素訪問很是快速。可是爲這種速度所付出的代價是數組對象的大小固定,而且在其生命週期中不可改變。
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
*///:~

數組的優勢是效率。設計模式

16.2 數組是第一級對象

不管使用哪一種類型的數組,數組標識符其實只是一個引用,指向在堆中建立的一個真實對象,這個對象用以保存指向其餘對象的引用。
對象數組和基本類型數組在使用上幾乎是相同的。惟一區別就是對象數組保存的是引用,基本類型數組直接保存基本類型的值。數組

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
*///:~

16.3 返回一個數組

數組的清理由垃圾回收機制負責。安全

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]
*///:~

16.4 多維數組

對於基本類型得多維數組,能夠經過使用花括號將每一個向量隔開: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]]
*///:~

16.5 數組與泛型

數組與泛型不能很好的結合。你不能實例化具備參數化類型的數組。
擦除會移除參數類型信息,而數組必須知道它們所持有的確切類型,以強制保證類型安全。
參數化數組自己的類型:

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]; }
} ///:~

16.6 建立測試數據

16.6.1 Arrays.fill()

只能用一個值填充各個位置,而針對對象而言,就是複製同一個引用進行填充:

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()能夠填充整個數組,或者只填充某個區域。

16.6.2 數據生成器

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();
        }
    }
}

16.6.3 從Generator中建立數組

這個工具只能產生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;
    }
}

16.7 Arrays實用功能

Arrays類有一套用於static實用方法,它有六個基本方法:equals()比較數組,deepEquals()比較多維數組;fill()填充;sort()用於對數組排序;binarySearch()用於在排序的數組中查找元素;toString()產生數組的String表示;hashCode()產生數組的散列碼。

16.7.1 複製數組

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()不會執行自動包裝,兩個數組必須具備相同的確切類型。

16.7.2 數組的比較

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
*///:~

16.7.3 數組元素的比較

排序必須根據對象的實際類型執行比較操做。
程序設計的基本目標是:將保存不變的事物與會發生改變的事物相分離。這裏,不變的是通用的排序算法,變化的是各類對象相互比較的方式。經過使用策略設計模式,能夠將會發生變化的代碼封裝在單獨的類中(策略對象),你能夠將策略對象傳遞給老是相同的代碼。
一種比較實現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]
]
*///:~

16.7.4 數組排序

使用內置的排序方法,就能夠對任意的基本類型數組排序,也能夠對任意的對象數組進行排序,只要該對象實現了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));
  }
}

排序算法針對正排序的特殊類型進行了優化——針對基本類型設計的"快速排序",以及針對對象設計的"穩定歸併排序"。

16.7.5 在已排序的數組中查找

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
*///:~
相關文章
相關標籤/搜索