thinking-in-java(16) 数组
?1)數組與其他類型容器的區別: 效率,類型和保持基本類型的能力;
?數組是效率最高的存儲和隨機訪問對象引用序列的方式;
?數組大小固定,容器大小可以不固定,所以這增加了彈性開銷,使得ArrayList的效率比數組低很多;
?
?【荔枝-數組與泛型容器的比較】? 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();// Arrays.toString() 打印數組各個元素的toString()print("Arrays.toString(spheres) = " + Arrays.toString(spheres)); print("spheres[4] = " + spheres[4]);// 容器List<BerylliumSphere> sphereList = new ArrayList<BerylliumSphere>();for(int i = 0; i < 5; i++)sphereList.add(new BerylliumSphere());print("sphereList = " + sphereList);print("sphereList.get(4) = " + sphereList.get(4));int[] integers = { 0, 1, 2, 3, 4, 5 };print("Arrays.toString(integers) = " + Arrays.toString(integers));print("integers[4] = " + integers[4]);// 用一個List A存放另外一個List B的元素(另外一個List B的大小是不可變的,但一個List A, 即intList的大小是可變的 )List<Integer> intList = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5));intList.add(97);print("intList = " + intList);print("intList.get(4) = " + intList.get(4));} } /* Arrays.toString(spheres) = [Sphere 0, Sphere 1, Sphere 2, Sphere 3, Sphere 4, null, null, null, null, null] spheres[4] = Sphere 4 sphereList = [Sphere 5, Sphere 6, Sphere 7, Sphere 8, Sphere 9] sphereList.get(4) = Sphere 9 Arrays.toString(integers) = [0, 1, 2, 3, 4, 5] integers[4] = 4 intList = [0, 1, 2, 3, 4, 5, 97] intList.get(4) = 4 */ 2)隨著自動包裝機制的出現,容器可以和數組一樣存儲基本數據類型;數組的優點僅僅是效率;
【16.2】數組是第一級對象
1)只讀成員length:數組對象的一部分,表示數組對象可以存儲多少元素(length 是數組唯一可訪問的字段);
2)[]語法:是訪問數組對象唯一的方式;
3)唯一區別:對象數組保存的是引用,基本類型數組保存基本類型的值;
【荔枝-初始化數組的方式】
// 對象數組和基本類型數組的比較荔枝 public class ArrayOptions {public static void main(String[] args) {// 對象數組BerylliumSphere[] a; // 本地未初始化BerylliumSphere[] b = new BerylliumSphere[5];// 數組中的引用自動初始化為 nullprint("BerylliumSphere[] b = new BerylliumSphere[5]; Arrays.toString(b) = " + Arrays.toString(b));BerylliumSphere[] c = new BerylliumSphere[4];for(int i = 0; i < c.length; i++) // length 是數組唯一可訪問的字段if(c[i] == null) c[i] = new BerylliumSphere();// 聚集初始化(在兩種情況下,尾隨逗號都是可選的)BerylliumSphere[] d = { new BerylliumSphere(),new BerylliumSphere(), new BerylliumSphere(),};// 動態聚集初始化(在兩種情況下,尾隨逗號都是可選的)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 = d; a.length = " + a.length);// 基本類型數組int[] e; // 空引用 //!print("e.length = " + e.length); // 編譯報錯:參數e 未初始化int[] f = new int[5];// 基本類型數組中的基本類型值自動初始化為 0 print("int[] f = new int[5]; Arrays.toString(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 };print("g.length = " + g.length);print("int[] h = { 11, 47, 93 }; h.length = " + h.length);e = h;print("e = h; e.length = " + e.length);e = new int[]{ 1, 2 };print("e = new int[]{ 1, 2 }; e.length = " + e.length);} } /* BerylliumSphere[] b = new BerylliumSphere[5]; Arrays.toString(b) = [null, null, null, null, null] a.length = 2 b.length = 5 c.length = 4 d.length = 3 a = d; a.length = 3 int[] f = new int[5]; Arrays.toString(f) = [0, 0, 0, 0, 0] g.length = 4 int[] h = { 11, 47, 93 }; h.length = 3 e = h; e.length = 3 e = new int[]{ 1, 2 }; e.length = 2 */ 4)數組的小缺點:?無法知道數組中確切有多少元素,因為length是數組的大小,并不是實際保存的元素個數;5)數組初始化策略:?初始化引用類型為null,基本類型數值型為0,字符型為 '\0'(轉換為int類型時,值等于0);布爾型為false;
6)聚集初始化: 隱式地使用 new 在堆中創建,就像數組一樣;
7)聚集初始化和動態聚集初始化的區別:?聚集初始化必須在定義數組的位置調用,而動態聚集初始化可以在任意位置創建和初始化對象;
【16.3】返回一個數組
【荔枝-直接返回一個數組】
// 方法返回一個數組的荔枝(C+ 和 C++的方法不能返回一個數組而返回一個指針) 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]; // 默認falsefor(int i = 0; i < n; i++) {int t;do {t = rand.nextInt(FLAVORS.length); // 產生小于 FLAVORS.length 的隨機數} while(picked[t]);results[i] = FLAVORS[t]; picked[t] = true;// while(picked[t]) 和 picked[t] = true; 的寫法非常經典 以確保不會重復選擇!!}return results; // 返回一個 String[] 數組}public static void main(String[] args) {for(int i = 0; i < 7; i++)System.out.println(Arrays.toString(flavorSet(3)));} } /* [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】多維數組
1)創建多維數組:對于基本類型的多維數組,可以通過使用 花括號 把每個向量分隔開;
【荔枝-創建多維基本類型數組】
// 荔枝-創建多維基本類型數組 public class MultidimensionalPrimitiveArray {public static void main(String[] args) {// 基本類型的多維數組 int[][] a = { { 1, 2, 3, },{ 4, 5, 6, },};// Arrays.deepToString(a), Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println(Arrays.deepToString(a));} } // [[1, 2, 3], [4, 5, 6]]【荔枝-使用 new關鍵字創建數組】 // 【荔枝-使用 new關鍵字創建數組】 public class ThreeDWithNew {public static void main(String[] args) {// 采用new 關鍵字創建 長度固定的3維基本類型數組, 默認為0 int[][][] a = new int[2][2][4];// Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println(Arrays.deepToString(a)); } } // [[[0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]]【注意-Arrays.toString(array)是把一維數組轉換為多個String;Arrays.deepToString()把多維數組轉換為多個String】
區別1:toString的輸入參數既可以是 基本數據類型也可以是引用類型;而deepToString的輸入參數只能是引用類型(Object[]);
區別2:toString 僅能夠把一維數組轉換為多個String,不能把2維度或以上維度的數組轉換為多個String,對于大于等于2維以上的數組,toString只能返回其內存地址的hashcode;
相反deepToString 可以轉換所有維度的數組為多個String,非常棒;
【荔枝-使用 new關鍵字創建數組(Arrays.toString(array)與Arrays.deepToString(array)區別)】
public class ThreeDWithNew {public static void main(String[] args) {// 采用new 關鍵字創建 長度固定的3維基本類型數組, 默認為0 Integer[][][] a = new Integer[2][2][4];// 1.轉換3維數組:// Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println("Arrays.deepToString(a)) = " + Arrays.deepToString(a));// 注意Arrays.deepToString() 和 Arrays.toString()方法的區別System.out.println("Arrays.deepToString(a)) = " + Arrays.toString(a));// 2.轉換2維數組:System.out.println("Arrays.deepToString(a[0]) = " + Arrays.deepToString(a[0]));System.out.println("Arrays.toString(a[0]) = " + Arrays.toString(a[0]));// 3.轉換1維數組:System.out.println("Arrays.deepToString(a)) = " + Arrays.deepToString(a[0][0]));System.out.println("Arrays.deepToString(a)) = " + Arrays.toString(a[0][0]));} } /* Arrays.deepToString(a)) = [[[null, null, null, null], [null, null, null, null]], [[null, null, null, null], [null, null, null, null]]] Arrays.deepToString(a)) = [[[Ljava.lang.Integer;@6d06d69c, [[Ljava.lang.Integer;@70dea4e] Arrays.deepToString(a[0]) = [[null, null, null, null], [null, null, null, null]] Arrays.toString(a[0]) = [[Ljava.lang.Integer;@7852e922, [Ljava.lang.Integer;@4e25154f] Arrays.deepToString(a)) = [null, null, null, null] Arrays.deepToString(a)) = [null, null, null, null] */ 3)粗糙數組或不規則數組:每個數組向量的長度不相同;
【荔枝-創建粗糙數組或不規則數組】
// 創建基本類型的粗糙數組,即每個數組向量的長度不相同;(也叫不規整數組) public class RaggedArray {public static void main(String[] args) {Random rand = new Random(47);// 邊長向量的3維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)]; // 這里的數組長度是隨機的 }// Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println(Arrays.deepToString(a));} } // [[], [[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]]] 【荔枝-創建引用類型的粗糙數組】// 創建引用類型的粗糙數組 public class MultidimensionalObjectArrays {public static void main(String[] args) {BerylliumSphere[][] spheres = {{ new BerylliumSphere(), new BerylliumSphere() }, // 長度為2{ new BerylliumSphere(), new BerylliumSphere(),new BerylliumSphere(), new BerylliumSphere() }, // 長度為4{ new BerylliumSphere(), new BerylliumSphere(),new BerylliumSphere(), new BerylliumSphere(),new BerylliumSphere(), new BerylliumSphere(),new BerylliumSphere(), new BerylliumSphere() }, // 長度為8};// Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println(Arrays.deepToString(spheres));} } /* [[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]] */ 【荔枝- 數組元素自動裝箱】
// 數組元素自動裝箱的荔枝(基本數據類型 轉換為 Integer 引用類型) public class AutoboxingArrays {public static void main(String[] args) {// 自動裝箱: int 基本數據類型 轉換為 Integer 引用類型// 基本類型數組 轉換為 引用類型數組 或 對象數組Integer[][] a = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },{ 21, 22, 23, 24, 25, 26, 27, 28, 29},{ 51, 52, 53, 54, 55, 56, 57, 58},{ 71, 72, 73, 74, 75, 76, 77, }, // 最后的逗號 可加 也可以不加};// Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println(Arrays.deepToString(a));} } /* [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [21, 22, 23, 24, 25, 26, 27, 28, 29], [51, 52, 53, 54, 55, 56, 57, 58], [71, 72, 73, 74, 75, 76, 77]] */ 【荔枝-運用自動裝箱機制對非基本類型的對象數組進行賦值】 // 運用自動裝箱機制對非基本類型的對象數組進行賦值的荔枝 public class AssemblingMultidimensionalArrays {public static void main(String[] args) {Integer[][] a;a = new Integer[3][];for(int i = 0; i < a.length; i++) {a[i] = new Integer[3];for(int j = 0; j < a[i].length; j++)a[i][j] = i * j; // 自動裝箱機制}// Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println(Arrays.deepToString(a));} } /* [[0, 0, 0], [0, 1, 2], [0, 2, 4]] */ 【荔枝-Arrays.deepToString() 只能接受Object[] 類型數組,而不是接受基本類型,但基本類型的包裝器類型是可以的;】
// Arrays.deepToString() 方法對基本類型數組和對象數組都起作用; 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" },};// Arrays.deepToString(Array array) 可以把多維數組轉換為多個 String;System.out.println("a1 = " + Arrays.deepToString(a1));System.out.println("a2 = " + Arrays.deepToString(a2));System.out.println("a3 = " + Arrays.deepToString(a3));} } /* Arrays.deepToString() 源碼: 只能接受Object[] 類型數組,而不是接受基本類型,但基本類型的包裝器類型是可以的;public static String deepToString(Object[] a) {if (a == null)return "null";int bufLen = 20 * a.length;if (a.length != 0 && bufLen <= 0)bufLen = Integer.MAX_VALUE;StringBuilder buf = new StringBuilder(bufLen);deepToString(a, buf, new HashSet<Object[]>());return buf.toString();} */ /* 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】數組與泛型
1)數組和泛型無法很好結合: 無法實例化具有參數化類型的數組;
Animal<Yaan>[] animals = new Animal<Yaan>[10]; // 這是非法的;
2)泛型擦除:會移除參數類型參數,而數組必須知道存儲元素的確切類型,這就矛盾了;
3)可以參數化數組本身的類型:
4)如何間接創建泛型數組:先創建非泛型數組,然后將其轉換為泛型數組;
【荔枝-間接實現泛型數組的荔枝(非常經典)】
// 間接實現泛型數組的荔枝-創建非泛型數組,然后將其轉型 為泛型容器類型 public class ArrayOfGenerics {@SuppressWarnings("unchecked")public static void main(String[] args) {List<String>[] ls;List[] la = new List[10];ls = (List<String>[])la; // 強制類型轉換,ls[0] = new ArrayList<String>(Arrays.asList("str1, str2, str3"));// 編譯時檢查 報錯://! ls[1] = new ArrayList<Integer>(); // 這個的泛型是Integer,而ls被賦值為 String泛型,肯定報錯啊;// The problem: List<String> is a subtype of Object// List<String> 是 Object 的子類型 ,所以賦值是可以的;Object[] objects = ls; // 編譯和運行無誤objects[1] = new ArrayList<Integer>(Arrays.asList(new Integer[]{1, 2, 3})); // 注意:這里居然編譯和運行通過;for (int i = 0; i < objects.length; i++) {System.out.println("objects[" + i +"] = " + objects[i]);}// 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>();} } /* objects[0] = [str1, str2, str3] objects[1] = [1, 2, 3] objects[2] = null objects[3] = null objects[4] = null objects[5] = null objects[6] = null objects[7] = null objects[8] = null objects[9] = null */ 【荔枝-如何創建泛型數組(先創建Object[]數組,然后將其轉型為泛型數組)】// 荔枝-如何創建泛型數組(先創建Object[] 數組,然后將其轉型為泛型數組) public class ArrayOfGenericType<T> {T[] array; // OK@SuppressWarnings("unchecked") // 阻止彈出 "不受檢查" 的警告信息public ArrayOfGenericType(int size) {//! array = new T[size]; // 非法, 不能創建泛型數組;// 阻止彈出 "不受檢查" 的警告信息 // 但是可以創建非泛型數組Object[],然后通過強制類型轉換,轉換為泛型數組;(間接創建泛型數組)array = (T[])new Object[size]; }//非法, 不能創建泛型數組;//! public <U> U[] makeArray() { return new U[10]; } } 【16.6】創建測試數據:使用對象或數值來填充數組
【16.6.1】Arrays.fill() 方法
// 荔枝-Arrays.fill() 填充數組 public class FillingArrays {public static void main(String[] args) {int size = 6;boolean[] a1 = new boolean[size]; // boolean 布爾數組byte[] a2 = new byte[size]; // byte 字節數組 char[] a3 = new char[size]; // char 字符數組short[] a4 = new short[size]; // short 短整型數組int[] a5 = new int[size]; // int 整型數組 long[] a6 = new long[size]; // long 長整型數組float[] a7 = new float[size]; // float 浮點型數組double[] a8 = new double[size]; // double 雙浮點型數組String[] a9 = new String[size]; // String 字符串數組Arrays.fill(a1, true); // 填充boolean 布爾數組print("Arrays.fill(a1, true); a1 = " + Arrays.toString(a1));Arrays.fill(a2, (byte)11); // 填充 byte 字節數組 print("Arrays.fill(a2, (byte)11); a2 = " + Arrays.toString(a2));Arrays.fill(a3, 'x'); // 填充 char 字符數組print("Arrays.fill(a3, 'x'); a3 = " + Arrays.toString(a3));Arrays.fill(a4, (short)17); // 填充 short 短整型數組print("Arrays.fill(a4, (short)17); a4 = " + Arrays.toString(a4));Arrays.fill(a5, 19); // 填充 int 整型數組 print("Arrays.fill(a5, 19); a5 = " + Arrays.toString(a5));Arrays.fill(a6, 23); // 填充 long 長整型數組print("Arrays.fill(a6, 23); a6 = " + Arrays.toString(a6));Arrays.fill(a7, 29); // 填充 float 浮點型數組print("Arrays.fill(a7, 29); a7 = " + Arrays.toString(a7));Arrays.fill(a8, 47); // 填充 double 雙浮點型數組print("Arrays.fill(a8, 47); a8 = " + Arrays.toString(a8));Arrays.fill(a9, "Hello"); // 填充 String 字符串數組print("Arrays.fill(a9, \"Hello\"); a9 = " + Arrays.toString(a9));// 這里是填充數組的某個區域Arrays.fill(a9, 3, 5, "World"); // 填充 String 字符串數組(下標3 到下標5,不包括下標5,從0開始計數)print("Arrays.fill(a9, 3, 5, \"World\"); a9 = " + Arrays.toString(a9));} } /* Arrays.fill(a1, true); a1 = [true, true, true, true, true, true] Arrays.fill(a2, (byte)11); a2 = [11, 11, 11, 11, 11, 11] Arrays.fill(a3, 'x'); a3 = [x, x, x, x, x, x] Arrays.fill(a4, (short)17); a4 = [17, 17, 17, 17, 17, 17] Arrays.fill(a5, 19); a5 = [19, 19, 19, 19, 19, 19] Arrays.fill(a6, 23); a6 = [23, 23, 23, 23, 23, 23] Arrays.fill(a7, 29); a7 = [29.0, 29.0, 29.0, 29.0, 29.0, 29.0] Arrays.fill(a8, 47); a8 = [47.0, 47.0, 47.0, 47.0, 47.0, 47.0] Arrays.fill(a9, "Hello"); a9 = [Hello, Hello, Hello, Hello, Hello, Hello] Arrays.fill(a9, 3, 5, "World"); a9 = [Hello, Hello, Hello, World, World, Hello] */ 【16.6.2】數據生成器
1)策略模式來填充數組:通過選擇Generator的類型來創建任何類型的數據,每個不同Generator都表示不同的策略;
【荔枝-通過靜態內部類實現數據生成器】
// 通過靜態內部類實現 數據生成器 public class CountingGenerator {// 通過靜態內部類實現public static class Boolean implements Generator<java.lang.Boolean> {private boolean value = false;public java.lang.Boolean next() {value = !value; // Just flips back and forthreturn value;}}public static class Byte implements Generator<java.lang.Byte> {private byte value = 0;public java.lang.Byte next() {return value++;}}static char[] chars = ("abcdefghijklmnopqrstuvwxyz"+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();public static class Character implements Generator<java.lang.Character> {int index = -1;public java.lang.Character next() {index = (index + 1) % chars.length;return chars[index];}}public static class String implements Generator<java.lang.String> {private int length = 7;Generator<java.lang.Character> cg = new Character();public String() {}public String(int length) {this.length = length;}public java.lang.String next() {char[] buf = new char[length];for (int i = 0; i < length; i++)buf[i] = cg.next(); // 通過字符生成字符串return new java.lang.String(buf);}}public static class Short implements Generator<java.lang.Short> {private short value = 0;public java.lang.Short next() {return value++;}}public static class Integer implements Generator<java.lang.Integer> {private int value = 0;public java.lang.Integer next() {return value++;}}public static class Long implements Generator<java.lang.Long> {private long value = 0;public java.lang.Long next() {return value++;}}public static class Float implements Generator<java.lang.Float> {private float value = 0;public java.lang.Float next() {float result = value;value += 1.0;return result;}}public static class Double implements Generator<java.lang.Double> {private double value = 0.0;public java.lang.Double next() {double result = value;value += 1.0;return result;}} } 【數據生成器的測試荔枝-通過策略模式來填充數組】?// 數據生成器的測試荔枝-策略模式來填充數組,其中利用反射機制來獲取 Class類實例數組 public class GeneratorsTest {public static int size = 10;public static void test(Class<?> surroundingClass) {// surroundingClass.getClasses() 獲取 Class類對應的內部類的Class類實例數組for(Class<?> type : surroundingClass.getClasses()) {System.out.print(type.getSimpleName() + ": ");try {// 傳入Class類信息,利用反射機制創建數據生成器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 */ 【荔枝-利用Random 創建隨機數據生成器的荔枝】
// 利用Random 創建隨機數據生成器的荔枝 public class RandomGenerator {private static Random r = new Random(47);public static class Boolean implements Generator<java.lang.Boolean> {public java.lang.Boolean next() {return r.nextBoolean();}}public static class Byte implements Generator<java.lang.Byte> {public java.lang.Byte next() {return (byte)r.nextInt(); // 調用的是 Random.nextInt()}}public static class Character implements Generator<java.lang.Character> {public java.lang.Character next() {// // 調用的是 Random.nextInt()return CountingGenerator.chars[r.nextInt(CountingGenerator.chars.length)];}}// 該 RandomGenerator.String 繼承自 CountingGenerator.String 類 (內部類繼承機制)public static class String extends CountingGenerator.String {// Plug in the random Character generator:{ cg = new Character(); } // Instance initializerpublic String() {}public String(int length) { super(length); }}public static class Short implements Generator<java.lang.Short> {public java.lang.Short next() {return (short)r.nextInt(); // 調用的是 Random.nextInt()}}public static class Integer implements Generator<java.lang.Integer> {private int mod = 10000;public Integer() {}public Integer(int modulo) { mod = modulo; }public java.lang.Integer next() {return r.nextInt(mod); // 調用的是 Random.nextInt()}}public static class Long implements Generator<java.lang.Long> {private int mod = 10000;public Long() {}public Long(int modulo) { mod = modulo; }public java.lang.Long next() {return new java.lang.Long(r.nextInt(mod)); // 調用的是 Random.nextInt()}}public static class Float implements Generator<java.lang.Float> {public java.lang.Float next() {// Trim all but the first two decimal places:int trimmed = Math.round(r.nextFloat() * 100); // 調用的是 Random.nextFloat()return ((float)trimmed) / 100;}}public static class Double implements Generator<java.lang.Double> {public java.lang.Double next() {long trimmed = Math.round(r.nextDouble() * 100); // 調用的是 Random.nextFloat()return ((double)trimmed) / 100;}} } /* Random.next*() 方法列表有: protected int next(int bits) { public void nextBytes(byte[] bytes) { final long internalNextLong(long origin, long bound) {public int nextInt() {return next(32); // next(bits=32) }public long nextLong() { public boolean nextBoolean() { public float nextFloat() { public double nextDouble() { */
【隨機數據生成器的測試荔枝-】
// 測試荔枝-利用隨機數據生成器填充數組 public class RandomGeneratorsTest {public static void main(String[] args) {GeneratorsTest.test(RandomGenerator.class);} } /* Double: 0.73 0.53 0.16 0.19 0.52 0.27 0.26 0.05 0.8 0.76 Float: 0.53 0.16 0.53 0.4 0.49 0.25 0.8 0.11 0.02 0.8 Long: 7674 8804 8950 7826 4322 896 8033 2984 2344 5810 Integer: 8303 3141 7138 6012 9966 8689 7185 6992 5746 3976 Short: 3358 20592 284 26791 12834 -8092 13656 29324 -1423 5327 String: bkInaMe sbtWHkj UrUkZPg wsqPzDy CyRFJQA HxxHvHq XumcXZJ oogoYWM NvqeuTp nXsgqia Character: x x E A J J m z M s Byte: -60 -17 55 -14 -5 115 39 -37 79 115 Boolean: false true false false true true true true true true */
【16.6.3】從Generator中創建數組
1)為了接受Generator 作為輸入參數并產生數組,需要兩個轉換工具:工具1)填充已有數組:接受一個已有數組a,并使用Generator 來填充該數組(填充已有數組)
工具2)創建新數組并填充:接受一個 Class對象 和 數組大小 來創建一個新數組,并用 Generator來填充該數組(創建新數組并填充)
// 荔枝-從Generator中創建數組 public class Generated {// 方法1:接受一個已有數組a,并使用Generator 來填充該數組(填充已有數組)public static <T> T[] array(T[] a, Generator<T> gen) {return new CollectionData<T>(gen, a.length).toArray(a);}@SuppressWarnings("unchecked")// 方法2:接受一個 Class對象 和 數組大小 來創建一個新數組,并用 Generator來填充該數組(創建新數組并填充)public static <T> T[] array(Class<T> type, Generator<T> gen, int size) {// 利用反射創建對象數組,全部賦值為 nullT[] a = (T[])java.lang.reflect.Array.newInstance(type, size);for ( T t : a ) {System.out.println("t = " + t);}return new CollectionData<T>(gen, size).toArray(a);}public static void main(String[] args) {Integer[] array = array(Integer.class, new RandomGenerator.Integer(), 5);System.out.println("after filling by generator, Arrays.toString(array) = " + Arrays.toString(array));} } /* t = null t = null t = null t = null t = null after filling by generator, Arrays.toString(array) = [9258, 555, 6693, 1861, 961] */ 【測試荔枝-從Generator中創建數組的兩個轉換工具】
// 測試荔枝-從Generator中創建數組的兩個轉換工具 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("a = " + Arrays.toString(a)); Integer[] b = Generated.array(Integer.class, new CountingGenerator.Integer(), 15);System.out.println("b = " + Arrays.toString(b)); } } /* [9, 8, 7, 6] a = [0, 1, 2, 3] t = null t = null t = null t = null t = null t = null t = null t = null t = null t = null t = null t = null t = null t = null t = null b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] */
2)數組類型轉換器:該轉換器可以接收任意的包裝器對象數組,并將其轉換為相應的基本類型數組;
【荔枝-為基本類型創建生成器】
// 荔枝-為基本類型創建生成器 public class ConvertTo {// Boolean 類型轉基本類型 booleanpublic static boolean[] primitive(Boolean[] in) {boolean[] result = new boolean[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;}// Character 類型轉基本類型 charpublic static char[] primitive(Character[] in) {char[] result = new char[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;}//Byte 類型轉基本類型 bytepublic static byte[] primitive(Byte[] in) {byte[] result = new byte[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;}//Short 類型轉基本類型 shortpublic static short[] primitive(Short[] in) {short[] result = new short[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;}//Integer 類型轉基本類型 intpublic static int[] primitive(Integer[] in) {int[] result = new int[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;}//Long 類型轉基本類型 longpublic static long[] primitive(Long[] in) {long[] result = new long[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;}// Float 類型轉基本類型 floatpublic static float[] primitive(Float[] in) {float[] result = new float[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;}//Double 類型轉基本類型 doublepublic static double[] primitive(Double[] in) {double[] result = new double[in.length];for(int i = 0; i < in.length; i++)result[i] = in[i]; // 自動拆箱return result;} } 【ConvertTo()的測試荔枝1-如何把 ConvertTo(為基本類型創建生成器) 應用于 array(Class<T> type, Generator<T> gen, int size)? 方法上】 // 荔枝-如何把 ConvertTo(為基本類型創建生成器) 應用于 array(Class<T> type, Generator<T> gen, int size) 方法上 public class PrimitiveConversionDemonstration {public static void main(String[] args) {Integer[] a = Generated.array(Integer.class, new CountingGenerator.Integer(), 15);int[] b = ConvertTo.primitive(a);System.out.println("int[] b = ConvertTo.primitive(a); b = " + Arrays.toString(b));boolean[] c = ConvertTo.primitive(Generated.array(Boolean.class, new CountingGenerator.Boolean(), 7));System.out.println("boolean[] c = ConvertTo.primitive(Generated.array(Boolean.class, new CountingGenerator.Boolean(), 7)); \n c = " + Arrays.toString(c));} } /* int[] b = ConvertTo.primitive(a); b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] boolean[] c = ConvertTo.primitive(Generated.array(Boolean.class, new CountingGenerator.Boolean(), 7)); c = [true, false, true, false, true, false, true] */【ConvertTo()的測試荔枝2-如何把 ConvertTo(為基本類型創建生成器) 應用于 array(Class<T> type, Generator<T> gen, int size) 方法上】
//荔枝-如何把 ConvertTo(為基本類型創建生成器) 應用于 array(Class<T> type, Generator<T> gen, int size) 方法上 public class TestArrayGeneration {public static void main(String[] args) {int size = 6;boolean[] a1 = ConvertTo.primitive(Generated.array(Boolean.class, new RandomGenerator.Boolean(), size));print("a1 = " + Arrays.toString(a1));byte[] a2 = ConvertTo.primitive(Generated.array(Byte.class, new RandomGenerator.Byte(), size));print("a2 = " + Arrays.toString(a2));char[] a3 = ConvertTo.primitive(Generated.array(Character.class, new RandomGenerator.Character(), size));print("a3 = " + Arrays.toString(a3));short[] a4 = ConvertTo.primitive(Generated.array(Short.class, new RandomGenerator.Short(), size));print("a4 = " + Arrays.toString(a4));int[] a5 = ConvertTo.primitive(Generated.array(Integer.class, new RandomGenerator.Integer(), size));print("a5 = " + Arrays.toString(a5));long[] a6 = ConvertTo.primitive(Generated.array(Long.class, new RandomGenerator.Long(), size));print("a6 = " + Arrays.toString(a6));float[] a7 = ConvertTo.primitive(Generated.array(Float.class, new RandomGenerator.Float(), size));print("a7 = " + Arrays.toString(a7));double[] a8 = ConvertTo.primitive(Generated.array(Double.class, new RandomGenerator.Double(), size));print("a8 = " + Arrays.toString(a8));} } /* a1 = [true, false, true, false, false, true] a2 = [104, -79, -76, 126, 33, -64] a3 = [Z, n, T, c, Q, r] a4 = [-13408, 22612, 15401, 15161, -28466, -12603] a5 = [7704, 7383, 7706, 575, 8410, 6342] a6 = [7674, 8804, 8950, 7826, 4322, 896] a7 = [0.01, 0.2, 0.4, 0.79, 0.27, 0.45] a8 = [0.16, 0.87, 0.7, 0.66, 0.87, 0.59] */
【16.7】Arrays實用功能
1)7個Arrays的基本方法:equals():用于比較兩個數組是否相等;
deepEquals():用于比較兩個多維數組是否相等;
fill():填充數組;
sort():對數組排序;
binarySearch():在有序的數組中查找元素;
toString():產生數組的String表示;
hashCode():產生數組的 hash code 散列碼;
以上方法都對各種基本類型和Object類重載過;
【16.7.1】復制數組(System.arraycopy())
1)System.arraycopy():用于復制數組,該方法對所有類型做了重載;
【荔枝-使用arraycopy() 復制數組】
// 荔枝-使用 System.arraycopy() 進行數組拷貝 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("Arrays.fill(i, 47); i = " + Arrays.toString(i)); // i = [47, 47, 47, 47, 47, 47, 47]print("Arrays.fill(j, 99); j = " + Arrays.toString(j)); // j = [99, 99, 99, 99, 99, 99, 99, 99, 99, 99]// System.arraycopy(i, 0, j, 0, i.length); 復制數組i從0到i.length(不包括)的元素 到 數組j(j從位置0開始存儲)System.arraycopy(i, 0, j, 0, i.length);// j = [47, 47, 47, 47, 47, 47, 47, 99, 99, 99]print("System.arraycopy(i, 0, j, 0, i.length); j = " + Arrays.toString(j)); int[] k = new int[5];Arrays.fill(k, 103);System.arraycopy(i, 0, k, 0, k.length);// k = [47, 47, 47, 47, 47]print("Arrays.fill(k, 103); System.arraycopy(i, 0, k, 0, k.length); k = " + Arrays.toString(k));Arrays.fill(k, 103);System.arraycopy(k, 0, i, 0, k.length); // 復制數組k[0,length-1] 到 數組i[0,length-]// i = [103, 103, 103, 103, 103, 47, 47]print("Arrays.fill(k, 103); System.arraycopy(k, 0, i, 0, k.length); i = " + Arrays.toString(i));// 對象數組Integer[] u = new Integer[10];Integer[] v = new Integer[5];Arrays.fill(u, new Integer(47));Arrays.fill(v, new Integer(99));// u = [47, 47, 47, 47, 47, 47, 47, 47, 47, 47]print("Arrays.fill(u, new Integer(47)); u = " + Arrays.toString(u));// v = [99, 99, 99, 99, 99]print("Arrays.fill(v, new Integer(99)); v = " + Arrays.toString(v));System.arraycopy(v, 0, u, u.length/2, v.length);// u = [47, 47, 47, 47, 47, 99, 99, 99, 99, 99]print("System.arraycopy(v, 0, u, u.length/2, v.length); u = " + Arrays.toString(u));} } /* Arrays.fill(i, 47); i = [47, 47, 47, 47, 47, 47, 47] Arrays.fill(j, 99); j = [99, 99, 99, 99, 99, 99, 99, 99, 99, 99] System.arraycopy(i, 0, j, 0, i.length); j = [47, 47, 47, 47, 47, 47, 47, 99, 99, 99] Arrays.fill(k, 103); System.arraycopy(i, 0, k, 0, k.length); k = [47, 47, 47, 47, 47] Arrays.fill(k, 103); System.arraycopy(k, 0, i, 0, k.length); i = [103, 103, 103, 103, 103, 47, 47] Arrays.fill(u, new Integer(47)); u = [47, 47, 47, 47, 47, 47, 47, 47, 47, 47] Arrays.fill(v, new Integer(99)); v = [99, 99, 99, 99, 99] System.arraycopy(v, 0, u, u.length/2, v.length); u = [47, 47, 47, 47, 47, 99, 99, 99, 99, 99] */ 【注意】arraycopy()方法不會執行自動包裝和自動拆包,兩個數組必須具有相同的確切類型;【16.7.2】數組比較(equals()方法)
1)數組相等的條件:數組元素個數必須相等,數組對應位置的元素也相等;
2)對于基本類型:需要使用基本類型的包裝器類的 equals()方法,如對int類型使用 Integer.equals()做比較;
【荔枝-數組比較】
// 荔枝-數組比較 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)); // true: a1 與 a2 相等a2[3] = 11; // 修改數組a2的某個元素print(Arrays.equals(a1, a2)); // false: 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)); // true: s1 與 s2 相等// 其實從 Arrays.equals(s1, s2) = true,可以看出 Arrays.equals() 比較的是 值是否相等,而不是引用是否相等} } /* Arrays.equals(Object a, Object a2) 源碼 public static boolean equals(Object[] a, Object[] a2) {if (a==a2)return true;if (a==null || a2==null)return false;int length = a.length;if (a2.length != length)return false;for (int i=0; i<length; i++) {Object o1 = a[i];Object o2 = a2[i];if (!(o1==null ? o2==null : o1.equals(o2)))return false;}return true; } */ 【16.7.3】數組元素比較1)使用策略模式進行比較: 把會發生變化的代碼封裝在單獨的類中(比較策略),然后把策略模式對象傳遞給總是相同的代碼,然后這些代碼再使用策略 模式對象來完成其比較;
2)java有兩種方式提供比較功能:
方式1)實現 java.lang.Comparable 接口,實現類有比較能力;
方式2)創建一個Comparator接口的實現類 來實現比較;
【方式1 荔枝-實現Comparable接口來比較】
// 使用策略模式,將策略對象傳遞給相同代碼,這些代碼使用策略來完成算法。 // 荔枝-java的兩種比較方式,一是實現 Comparable接口 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;}// 這里的比較策略只用到了 屬性i,沒有屬性jpublic 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("Arrays.toString(a) = " + Arrays.toString(a));Arrays.sort(a);print("Arrays.sort(a); Arrays.toString(a) = " + Arrays.toString(a));} } /* Arrays.sort() 源碼 public static void sort(Object[] a) {if (LegacyMergeSort.userRequested)legacyMergeSort(a);elseComparableTimSort.sort(a, 0, a.length, null, 0, 0); } */ /* 打印結果 Arrays.toString(a) = [[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] ] Arrays.sort(a); Arrays.toString(a) = [[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] ] */ 【注意】如果沒有實現 Comparable 接口,調用sort()方法的時候會拋出 ClassCastException 運行時異常。因為sort()方法需要把參數類型轉變為 Comparable;
/* java.lang.Comparable接口源碼 public interface Comparable<T> {public int compareTo(T o); } */ 3)Collections類包含一個 reverseOrder()方法,產生一個 Comparator實現類,以反轉自然的排序順序;
【方式2-荔枝-以反轉自然的排序順序對數組排序】
// 荔枝-以反轉自然的排序順序對數組排序 public class Reverse {public static void main(String[] args) {CompType[] a = Generated.array(new CompType[12], CompType.generator());print("Arrays.toString(a) = " + Arrays.toString(a));// CompType類的排序規則是 按照屬性 i 升序排序的。Arrays.sort(a); // 第 1 次排序print("Arrays.sort(a); Arrays.toString(a) = " + Arrays.toString(a));// Collections.reverseOrder() 反轉自然的排序順序( 按照屬性 i 降序排序的。)Arrays.sort(a, Collections.reverseOrder()); // 第 2 次排序 print("Arrays.sort(a, Collections.reverseOrder()); Arrays.toString(a) = " + Arrays.toString(a));} } /* Arrays.sort(T[] a, Comparator<? super T> c) 源碼public static <T> void sort(T[] a, Comparator<? super T> c) {if (c == null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);} } */ /* 打印結果 // 1.原始的數組是亂序的 Arrays.toString(a) = [[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] ] // 2.按照i 升序排序 Arrays.sort(a); Arrays.toString(a) = [[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] ] // 3.按照i 降序排序 Arrays.sort(a, Collections.reverseOrder()); Arrays.toString(a) = [[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] ] */ /* Collections.reverseOrder() 源碼:@SuppressWarnings("unchecked") public static <T> Comparator<T> reverseOrder() {return (Comparator<T>) ReverseComparator.REVERSE_ORDER; } ReverseComparator 源碼 private static class ReverseComparatorimplements Comparator<Comparable<Object>>, Serializable {private static final long serialVersionUID = 7207038068494060240L;static final ReverseComparator REVERSE_ORDER= new ReverseComparator();public int compare(Comparable<Object> c1, Comparable<Object> c2) {return c2.compareTo(c1);}private Object readResolve() { return Collections.reverseOrder(); }@Overridepublic Comparator<Comparable<Object>> reversed() {return Comparator.naturalOrder();} } */ /* */【方式2-荔枝-自定義 Comparator 對數組排序(通過實現 Comparator接口來實現)】
// 自定義排序規則的荔枝(通過實現 Comparator接口來實現) class CompTypeComparator implements Comparator<CompType> {// 排序規則: 按照 j 進行升序排序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("Arrays.toString(a) = " + Arrays.toString(a));Arrays.sort(a, new CompTypeComparator()); // 通過實現 Comparator接口來自定義排序規則對數組排序print("Arrays.sort(a, new CompTypeComparator()); Arrays.toString(a) = " + Arrays.toString(a));} } /* // 1.數組亂序 Arrays.toString(a) = [[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] ] // 2.按照 j 進行升序排序 Arrays.sort(a, new CompTypeComparator()); Arrays.toString(a) = [[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的區別:
區別1)重寫的方法不同:
實現 Comparable接口:需要重寫 public int compareTo(T o) 方法;需要比較的對象作為 Comparable實現類;
實現 Comparator接口:需要重寫? int compare(T o1, T o2) 方法;需要比較的對象 并不作為 Comparator實現類,而是其他的比較策略對象作為 Comparator實現類;
區別2)實現方式不同:
通過實現 Comparable 接口這種方式實現數組比較的特點:?將需要比較的對象 與 比較方法 的實現代碼 揉在一起 ;
通過實現 Comparator 接口這種方式實現數組比較的優點: 將需要比較的對象 與 比較方法 的實現代碼 分離開;區別3)最大的區別:基本類型數組無法使用 Comparator 進行排序;
【16.7.4】數組排序
1)數組排序的前提條件: 該對象實現了 Comparable 接口 或 有相關聯的 Comparator ;
【荔枝-基于多種排序策略對數組排序】
// 荔枝-基于多種排序策略對數組排序 public class StringSorting {public static void main(String[] args) {String[] sa = Generated.array(new String[20], new RandomGenerator.String(5));print("\nArrays.toString(sa) = " + Arrays.toString(sa));Arrays.sort(sa); // 自然排序print("\nArrays.sort(sa); Arrays.toString(sa) = " + Arrays.toString(sa));Arrays.sort(sa, Collections.reverseOrder()); // 逆序print("\nArrays.sort(sa, Collections.reverseOrder()); Arrays.toString(sa) = " + Arrays.toString(sa));Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER); // 忽略大小寫敏感print("\nArrays.sort(sa, String.CASE_INSENSITIVE_ORDER); Arrays.toString(sa) = " + Arrays.toString(sa));} } /* //1.原始數組 Arrays.toString(sa) = [YNzbr, nyGcF, OWZnT, cQrGs, eGZMm, JMRoE, suEcU, OneOE, dLsmw, HLGEa, hKcxr, EqUCB, bkIna, Mesbt, WHkjU, rUkZP, gwsqP, zDyCy, RFJQA, HxxHv] //2.自然排序后的數組 Arrays.sort(sa); Arrays.toString(sa) = [EqUCB, HLGEa, HxxHv, JMRoE, Mesbt, OWZnT, OneOE, RFJQA, WHkjU, YNzbr, bkIna, cQrGs, dLsmw, eGZMm, gwsqP, hKcxr, nyGcF, rUkZP, suEcU, zDyCy] //3.自然逆序排序后的數組 Arrays.sort(sa, Collections.reverseOrder()); Arrays.toString(sa) = [zDyCy, suEcU, rUkZP, nyGcF, hKcxr, gwsqP, eGZMm, dLsmw, cQrGs, bkIna, YNzbr, WHkjU, RFJQA, OneOE, OWZnT, Mesbt, JMRoE, HxxHv, HLGEa, EqUCB] //4.大小寫不敏感的自然排序后的數組 Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER); Arrays.toString(sa) = [bkIna, cQrGs, dLsmw, eGZMm, EqUCB, gwsqP, hKcxr, HLGEa, HxxHv, JMRoE, Mesbt, nyGcF, OneOE, OWZnT, RFJQA, rUkZP, suEcU, WHkjU, YNzbr, zDyCy] */ 【注意】 String 排序算法依據 詞典編排順序排序,所以大寫字母開頭的詞都排在前面,小寫字母的詞排在后面;(因為大寫字母的ASCII碼 小于 小寫字母的 ASCII碼)【干貨】java標準類庫中的排序算法對正排序的特殊類型進行了優化:針對基本類型設計的快速排序 或 針對對象設計的 穩定歸并排序。不需要擔心java對數組的排序性能;
【16.7.5】在已排序的數組中查找(Arrays.binarySearch() 二分查找)
【荔枝-Arrays.binarySearch() 對有序數組進行二分查找】 // 荔枝-Arrays.binarySearch() 對有序數組進行二分查找 public class ArraySearching {public static void main(String[] args) {Generator<Integer> gen = new RandomGenerator.Integer(1000);// 利用隨機數據生成器 產生Integer包裝器數組并 轉換為 int基本類型數組int[] a = ConvertTo.primitive(Generated.array(new Integer[25], gen));Arrays.sort(a); // 自然排序print("Arrays.sort(a); Arrays.toString(a) = " + Arrays.toString(a));while(true) {int r = gen.next();// Arrays.binarySearch(a, r); 在有序數組a中二分查找 rint location = Arrays.binarySearch(a, r); if(location >= 0) {print("Location of " + r + " is " + location +", a[" + location + "] = " + a[location]);break; }}} } /* Sorted array: [128, 140, 200, 207, 258, 258, 278, 288, 322, 429, 511, 520, 522, 551, 555, 589, 693, 704, 809, 861, 861, 868, 916, 961, 998] Location of 322 is 8, a[8] = 322 */ 1)Arrays.binarySearch(): 如果找到了目標,Arrays.binarySearch()產生的返回值等于或大于0;否則,返回值為負值,表示若要保持數組有序,該目標元素應該插入的位置;
2)上述負值計算方式:?- (插入點) - 1;插入點指的是,第一個大于查找對象的元素在數組中的位置,如果數組中的所有元素都小于目標元素,則插入點就是 a.size();
3)如果使用 Comparator 排序了某個對象數組(基本類型數組無法使用 Comparator 進行排序),在使用 binarySearch() 時也必須提供同樣的 Comparator;
// 荔枝-為二分查找 Arrays.binarySearch 設置排序規則 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.sort(sa, String.CASE_INSENSITIVE_ORDER); \nArrays.toString(sa) = " + Arrays.toString(sa));System.out.println("sa[10] = " + sa[10]);// 通過二分查找 查找出 sa[10] 元素的位置,其中排序規則同 Arrays.sort(sa) 的排序規則 String.CASE_INSENSITIVE_ORDER,否則報錯int index = Arrays.binarySearch(sa, sa[10], String.CASE_INSENSITIVE_ORDER);System.out.println("Index: "+ index + "\n"+ sa[index]);} } /* Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER); Arrays.toString(sa) = [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 */
【16.8】總結
1)使用容器來代替數組: 有了額外的自動包裝機制和泛型,在容器中持有基本類型就很容易了。這也促使使用 容器而不是數組。因為泛型可以產生類型安全的容器;2)優先容器而不是數組:只有在已證明性能稱為問題,并且切換到數組對性能有提高時,你才應該將程序重構為使用數組;
總結
以上是生活随笔為你收集整理的thinking-in-java(16) 数组的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 轻轻松松让Win7玩网游不再卡
- 下一篇: DevExperience(1712)