Think in Java第四版 读书笔记10 第16章 数组
数组和容器很像 但他们有一些差别


16.1 数组为什么特殊

数组与容器的区别主要在效率和存储类型
效率:数组是简单的线性序列 使得数组的访问很快 但是数组长度固定,没有容器灵活, 容器的灵活是需要系统付出更多的开销的。从访问效率上看 数组更高
存储类型:在没有泛型之前 数组可以存储固定类型的元素 而容器只能存储Object类型。容器一开始也不能存储基本类型,但是由于之后新增了包装类,容器也能存储基本类型了。
所以,由于新增的泛型和包装类 数组和容器在这点的区别已经不明显了。
数组VS容器例子

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 数组是一个引用

数组标识符是一个引用,它指向堆中创建的一个真实对象 该对象保存指向其他对象的引用,该对象还有一个只读成员length 下表[]是访问数组的唯一方式
例子:数组的各种初始化方式 以及 存储基本类型数组与对象数组的区别

// Initialization & re-assignment of arrays.
import java.util.*;
import static net.mindview.util.Print.*;public class ArrayOptions {public static void main(String[] args) {// 存储对象的数组:BerylliumSphere[] a; // 本地未初始化变量BerylliumSphere[] b = new BerylliumSphere[5];//创建长度为5的BerylliumSphere数组// b指向的五个对象的引用均初始化为空print("b: " + Arrays.toString(b));BerylliumSphere[] c = new BerylliumSphere[4];//创建长度为4的BerylliumSphere数组for (int i = 0; i < c.length; i++)if (c[i] == null) // Can test for null referencec[i] = new BerylliumSphere();// Aggregate initialization: 集合初始化// 另一种初始化BerylliumSphere[] d = { new BerylliumSphere(), new BerylliumSphere(),new BerylliumSphere() };// Dynamic aggregate initialization: 动态集合初始化// a的长度初始化为2a = 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;//a的引用指向d a的长度==d == 3print("a.length = " + a.length);// Arrays of primitives:// 基本类型数组int[] e; // Null reference 空引用// Compile error: variable e not initialized:// !print("e.length = " + e.length);// 不初始化无法调用lengthint[] f = new int[5];// 基本类型数组的初始值是0print("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("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*/// :~

1.数组没有初始化之前 不能做任何事情
2.bool类型数组元素默认初始化 false 其他基本类型默认初始化为0(char默认初始化为’\u0000’)


16.3 返回一个数组

Java返回引用 C++返回指针 Java则是返回数组的引用 感觉差不多。可能由于Java自动垃圾回收机制 即使新创建了数组也可以自动回收,而C++就没有这么方便了
例子:Java中返回String数组

import java.util.*;public class IceCream {private static Random rand = new Random(47);//创建一个string数组static final String[] FLAVORS = { "Chocolate", "Strawberry","Vanilla Fudge Swirl", "Mint Chip", "Mocha Almond Fudge","Rum Raisin", "Praline Cream", "Mud Pie" };//返回一个string数组public static String[] flavorSet(int n) {//simple judgmentif (n > FLAVORS.length)throw new IllegalArgumentException("Set too big");String[] results = new String[n];//创建了一个新的数组boolean[] picked = new boolean[FLAVORS.length];//创建和FLAVORS长度相等的boolean数组for (int i = 0; i < n; i++) {//对results遍历n次 进行初始化int t;do{t = rand.nextInt(FLAVORS.length);} while (picked[t]);results[i] = FLAVORS[t];//给新建的字符串数组赋值picked[t] = true;//标记当前下标的String已经被添加(避免出现重复字符)}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]*/// :~

上面这个例子在方法中创建了String 再举一个例子,说明一下 如果不创建新数组 直接返回数组的例子

public class Test{static final String[] FLAVORS = { "CCC", "DDD","FFF"};public static String [] test(){return FLAVORS;//没有创建新的数组 直接返回}public static void main(String args[]) throws InterruptedException {for(String string : FLAVORS){System.out.println(string);}System.out.println("======");String [] s = test();//s直接指向FLAVORS的地址 因此可以直接修改内容s[0] = "aaaa";//FLAVORS内容被修改的地方for(String string : s){System.out.println(string);}System.out.println("======");for(String string : FLAVORS){System.out.println(string);//确认FLAVORS内容被修改}}
}

个人觉得还是不要直接返回数组比较好 因为如果每次返回都是原数组,那么其他任意地方都可能修改其内容,那要检测其内容就会变得尤其困难。


16.4 多维数组

//多维数组的创建与输出
public class MultidimensionalPrimitiveArray {public static void main(String[] args) {int[][] a = { { 1, 2, 3, }, { 4, 5, 6, }, };// 初始化 使用花括号 创建一个2*3的二维数组System.out.println(Arrays.deepToString(a));//将多维数组(内容可以是基本数据类型或者Object)转换成多个String 可以看看deepToString源码}
} /** Output: [[1, 2, 3], [4, 5, 6]]*/// :~

public class ThreeDWithNew {public static void main(String[] args) {// 3-D array with fixed length:int[][][] a = new int[2][2][4];//使用new操作符创建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]]]
*///:~

//粗糙数组例子
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]]]
*///:~
//三维的感觉不好理解 拿二维的作比较 比如二维的正常数组像2*3 3*3 这种方方正正的数组
//粗糙数组则比如[[1,2],[1]]即这个二维数组 不是每个维度的长度一致(想象每个元素是一个小方块 通常的数组都是方方正正的 粗糙数组则不然)
//正常数组例子1(2*2)
//□ □
//□ □
//正常数组例子2(3*2)
//□ □
//□ □
//□ □
//二维粗糙数组例子1
//□ □
//□
//二维粗糙数组例子 2
//□ □ □
//□ □
//□ □ □ □ □
//实际中多维数组用的本身就比较少 这种各个长度都不相等的数组(粗糙数组)基本用不到 感觉不需要太在意

// 多维数组逐维初始化
import java.util.*;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; // Autoboxing}System.out.println(Arrays.deepToString(a));}
} /* Output:
[[0, 0, 0], [0, 1, 2], [0, 2, 4]]
*///:~

16.5 数组与泛型

无法直接创建泛型数组
List [] s = new List[10];//Cannot create a generic array of List


//类参数化和方法参数化 参数化数组本身的类型
class ClassParameter<T> {//类参数化 注意<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" warningls[0] = new ArrayList<String>();// Compile-time checking produces an error:// ! ls[1] = new ArrayList<Integer>();//编译期类型错误// The problem: List<String> is a subtype of ObjectObject[] 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]; }@SuppressWarnings("unchecked")public <U> U[] makeArray() {//this is OKreturn ((U[]) new Object[10]);}
} // /:~

16.6 创建测试数据

介绍各种工具填充数组

16.6.1 Arrays.fill

Arrays.fill可以用同一个值填充各个位置 如果填充的是对象 则赋值的都是该对象的引用


public class FillingArrays {public static void main(String[] args) {int size = 6;//创建长度为6的基本类型和string类型数组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填充数组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]*/// :~

16.6.2 数据生成器

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> {class Test1{}private byte value = 0;public java.lang.Byte next() {return value++;}}public static class Test2{}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;}}
} // /:~

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);for(Class type : CountingGenerator.class.getClasses()){System.out.println(type.getSimpleName());}}
} /** Output:
Boolean: true false true false true false true false true false
Byte: 0 1 2 3 4 5 6 7 8 9
Character: a b c d e f g h i j
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
Integer: 0 1 2 3 4 5 6 7 8 9
Long: 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 */// :~

16.6.3 从Generator中创建数组 略


16.7 Arrays实用功能

Arrays有6个基本方法
equals判断数组是否相等(deep Equals用于多维数组)
fill为数组填充单一元素
sort数组排序
binarySearch对已经排序的数据进行二分查找
toString产生数组的字符串形式
hashCode返回数组的哈希值

另:Arrays.asList接受任意序列或数组 返回一个List


16.7.1 复制数组

// Using System.arraycopy()
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);//将数组i中的内容复制给数组j 长度为i.lengthprint("j = " + Arrays.toString(j));int[] k = new int[5];Arrays.fill(k, 103);print("k = " + Arrays.toString(k));System.arraycopy(i, 0, k, 0, k.length);//如果使用i.length会越界print("k = " + Arrays.toString(k));Arrays.fill(k, 103);System.arraycopy(k, 0, i, 0, k.length);//将k的内容赋值给iprint("i = " + Arrays.toString(i));// Objects: 复制对象 注意此处为浅拷贝// 并需注意arraycopy不会进行自动装箱和拆箱 所以拷贝的类型必须一致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);//从0开始拷贝v的内容一直拷贝到末尾(长度5) 复制到u 起点index为10/2print("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 = [103, 103, 103, 103, 103]
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]*/// :~

16.7.2 数组的比较

public class ComparingArrays {public static void main(String[] args) {int[] b1 = new int[10];int[] b2 = new int[9];print(Arrays.equals(b1, b2));// 长度不一样 所以为falseint[] a1 = new int[10];int[] a2 = new int[10];print(Arrays.equals(a1, a2));// 初始值一样 长度一样 所以为trueArrays.fill(a1, 47);Arrays.fill(a2, 47);print(Arrays.equals(a1, a2));// 数值一样 长度一样 所以为truea2[3] = 11;print(Arrays.equals(a1, a2));// 其中一个数值不等  所以为falseString[] 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));//string的比较是先比较地址 再比较字符串中的每个字符 这里虽然地址不同 但是值相同 返回trueComparingArrays[] o1 = new ComparingArrays[4];Arrays.fill(o1, new ComparingArrays());ComparingArrays[] o2 = { new ComparingArrays(), new ComparingArrays(), new ComparingArrays(),new ComparingArrays() };print(Arrays.equals(o1, o2));//对象的比较是比较引用 引用不同所以不等}
} /** Output:
false
true
true
false
true
false*/// :~

16.7.3 数组元素的比较

数组中的元素实现Comparable接口 即可拥有比较功能
例子:实现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;}public int compareTo(CompType rv) {//只比较i的值 j的值忽略了 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]
]*/// :~

Arrays.sort方法内部会将参数直接转换成Comparable对象进行比较 如果没有实现Comparable接口 则会报类型转换错误


例子:反序排序

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进行不同的排序策略

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());//使用自定义Comparator进行排序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 数组排序

如果数组元素是基本数据类型或字符串类型 可以使用内置排序方法直接排序
例子:

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));}
} /** Output:
Before sort: [YNzbr, nyGcF, OWZnT, cQrGs, eGZMm, JMRoE, suEcU, OneOE, dLsmw, HLGEa, hKcxr, EqUCB, bkIna, Mesbt, WHkjU, rUkZP, gwsqP, zDyCy, RFJQA, HxxHv]
After sort: [EqUCB, HLGEa, HxxHv, JMRoE, Mesbt, OWZnT, OneOE, RFJQA, WHkjU, YNzbr, bkIna, cQrGs, dLsmw, eGZMm, gwsqP, hKcxr, nyGcF, rUkZP, suEcU, zDyCy]
Reverse sort: [zDyCy, suEcU, rUkZP, nyGcF, hKcxr, gwsqP, eGZMm, dLsmw, cQrGs, bkIna, YNzbr, WHkjU, RFJQA, OneOE, OWZnT, Mesbt, JMRoE, HxxHv, HLGEa, EqUCB]
Case-insensitive sort: [bkIna, cQrGs, dLsmw, eGZMm, EqUCB, gwsqP, hKcxr, HLGEa, HxxHv, JMRoE, Mesbt, nyGcF, OneOE, OWZnT, RFJQA, rUkZP, suEcU, WHkjU, YNzbr, zDyCy]*/// :~

Arrays.sort方法:

public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}

源码中可以看到 针对对象排序使用了归并排序
针对基本类型 如果继续跟踪代码可以看到使用的是二分排序


16.7.5 在已排序数组中查找元素

public class ArraySearching {public static void main(String[] args) {int[] a = {5,12,323432,1,66,33,2,4,99};Arrays.sort(a);print("Sorted array: " + Arrays.toString(a));int location = Arrays.binarySearch(a, 5);if (location >= 0) {print("Location of " + 5 + " is " + location + ", a["+ location + "] = " + a[location]);}}
} /** Output:
Sorted array: [1, 2, 4, 5, 12, 33, 66, 99, 323432]
Location of 5 is 3, a[3] = 5*/// :~

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

搜索时可以传入自定义Comparator 这种方式适用于对象的查找
我们应该优先使用容器而不是数组 在容器引入泛型之后 数组的优势几乎荡然无存,除非发现性能问题,才会使用数组,而这种情况也是微乎其微的。

Think in Java第四版 读书笔记10 第16章 数组相关推荐

  1. Think in Java第四版 读书笔记9第15章 泛型

    Think in Java第四版 读书笔记9第15章 泛型 泛型:适用于很多很多的类型 与其他语言相比 Java的泛型可能有许多局限 但是它还是有很多优点的. 本章介绍java泛型的局限和优势以及ja ...

  2. Think in Java第四版 读书笔记7第13章 字符串

    本章内容 1.string的基本使用 2.string拼接符 + 3.Object方法toString 4.String的常用方法 5.String的格式化输出 6.正则表达式 13.1 不可变字符串 ...

  3. Think in Java第四版 读书笔记6第12章 异常处理

    12.1 概念 异常可以将"在正常时候执行的代码"和"发生错误时的代码"相分离,达到结构清晰的目的. a.受检查异常checkedException 编译器强制 ...

  4. Think in Java第四版 读书笔记8第14章 类型信息(RTTI与反射)

    Java如何在运行时识别对象和类的信息? 1.RTTI(Run-time type information) 它假定我们在编译时已经知道了所有类型 2.反射 它允许我们在运行时发现和使用类的信息 14 ...

  5. Think in Java第四版 读书笔记5第11章

    第十一章 持有对象(主要讲容器类) 概要 通常程序中我们需要一些容器来存储对象或者对象的引用 在java中承担这一责任的是数组和容器类 数组VS容器类 数组存在一个缺陷:长度固定不够灵活 而容器类则没 ...

  6. Think in Java第四版 读书笔记3第七章第八章

    第七章复用类 复用代码的方式 1组合 2继承 方式1组合 public class Box {String boxName;public Box(String s) {System.out.print ...

  7. Think In Java第四版读书笔记

    02-一切都是对象 将一切都"看作"对象,操纵的标识符实际是指向一个对象的"句柄". 可将这一情形想象成用遥控板(句柄)操纵电视机(对象). String s; ...

  8. Think in Java第四版 读书笔记2

    习题答案 http://greggordon.org/java/tij4/solutions.htm 第四章 控制流程(本节很简单,很多内容掠过) if else if else if while d ...

  9. Think in Java第四版 读书笔记1

    第一章对象导论(Java的几个重要部分) 访问控制的目的: 1.权限控制 2.类创建者修改某些实现而不会影响类使用者 代码复用的方式: 1.继承 2.组合(composition UML中实心菱形+实 ...

最新文章

  1. Angular里使用createEmbeddedView的单步调试
  2. 中文验证码 php_还在苦恼验证码怎么实现?看看这个验证码组件合集,你想要的都有...
  3. torchtext处理文本数据——将文本变为embedding(学习三)
  4. 基于图像界面工具postman进行测试
  5. ASP.NET - 一般处理程序获取session值
  6. Android UI学习之Gallery
  7. Mac 上使用vim 快捷键
  8. 掀开Dubbo的盖头来
  9. linux桌面lxde 安装_Ubuntu下安装LXDE桌面+noVNC直接WEB管理
  10. 6.JUC-共享模型之工具
  11. 高考选地理化学生物能考计算机专业吗,高考选科物理化学地理可以报考什么专业...
  12. 小波科普文章精粹:看森林,也看树木
  13. Pub failed to delete entry because it was in use by anothe
  14. MTK平台俄罗斯方块游戏评审
  15. 30秒集结会议、能开“会中会” IMO班聊助力高效协同办公
  16. 微软股价 2019 年飙升 55.3%,创十年来最佳表现!
  17. 形容口蜜腹剑图片_“口蜜腹剑”形容一个人两面三刀,可你知道成语说的是谁吗?...
  18. EM算法-Jensen不等式
  19. SSM中的拦截器机制
  20. 培训班出身的同学简历怎么做?面试要注意哪些?来自资深大厂HR的忠告

热门文章

  1. mysql 存储过程 输出table_mysql 存储过程 没有结果输出。
  2. python 递归遍历目录排序_python下递归遍历目录和文件
  3. android 呼吸灯权限_小米新机搭载炫彩呼吸灯酷到爆;三星顶级旗舰Note 10正式官宣...
  4. linux上jar包的运行
  5. Linux下ftp的安装配置
  6. 为ASP.NET MVC应用添加自定义路由
  7. linux 下安装ftp服务器
  8. 3G手机Android应用开发视频教程_黎活明老师的视频(第三天课程)总共有八天课程...
  9. CCF201712-2 游戏
  10. java实现pop客户机程序_java客户机如何通过JEE服务器(如weblogic、jboss等)进行身份验证的概念...