Think in Java第四版 读书笔记10 第16章 数组

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 sphereList = new ArrayList();
		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 intList = new ArrayList(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 reference
				c[i] = new BerylliumSphere();
		// Aggregate initialization: 集合初始化
		// 另一种初始化
		BerylliumSphere[] d = { new BerylliumSphere(), new BerylliumSphere(),
				new BerylliumSphere() };
		// Dynamic aggregate initialization: 动态集合初始化
		// a的长度初始化为2
		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;//a的引用指向d a的长度==d == 3
		print("a.length = " + a.length);

		// Arrays of primitives:
		// 基本类型数组
		int[] e; // Null reference 空引用
		// Compile error: variable e not initialized:
		// !print("e.length = " + e.length);
		// 不初始化无法调用length
		int[] f = new int[5];
		// 基本类型数组的初始值是0
		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 };
		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
 */// :~

Think in Java第四版 读书笔记10 第16章 数组_第1张图片

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 judgment
		if (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 {//类参数化 注意的位置
	public T[] f(T[] arg) {
		return arg;
	}
}

class MethodParameter {//方法参数化 应是首选
	public static  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().f(ints);//声明的地方不可以使用泛型 但赋值可以
		Double[] doubles2 = new ClassParameter().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[] ls;//创建一个泛型数组的引用
		List[] la = new List[10];//创建一个普通数组
		ls = (List[]) la; // "Unchecked" warning
		ls[0] = new ArrayList();
		// Compile-time checking produces an error:
		// ! ls[1] = new ArrayList();//编译期类型错误

		// The problem: List is a subtype of Object
		Object[] objects = ls; // So assignment is OK
		// Compiles and runs without complaint:
		objects[1] = new ArrayList();//正常编译

		// However, if your needs are straightforward it is
		// possible to create an array of generics, albeit
		// with an "unchecked" warning:
		//如果你想创建泛型数组 是可行的,不过需要压制未检查异常和强制类型转换
		List[] spheres = (List[]) new List[10];
		for (int i = 0; i < spheres.length; i++)
			spheres[i] = new ArrayList();
	}
} // /:~

使用泛型

public class ArrayOfGenericType {
	T[] array; // OK

	@SuppressWarnings("unchecked")
	public ArrayOfGenericType(int size) {
		// ! array = new T[size]; // Illegal//不能直接创建
		array = (T[]) new Object[size]; // "unchecked" Warning
	}

	// Illegal:
	// ! public  U[] makeArray() { return new U[10]; }
	@SuppressWarnings("unchecked")
	public  U[] makeArray() {//this is OK
		return ((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 {
		private boolean value = false;

		public java.lang.Boolean next() {
			value = !value; // Just flips back and forth
			return value;
		}
	}

	public static class Byte implements Generator {
		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 {
		int index = -1;

		public java.lang.Character next() {
			index = (index + 1) % chars.length;
			return chars[index];
		}
	}

	public static class String implements Generator {
		private int length = 7;
		Generator 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 {
		private short value = 0;

		public java.lang.Short next() {
			return value++;
		}
	}

	public static class Integer implements Generator {
		private int value = 0;

		public java.lang.Integer next() {
			return value++;
		}
	}

	public static class Long implements Generator {
		private long value = 0;

		public java.lang.Long next() {
			return value++;
		}
	}

	public static class Float implements Generator {
		private float value = 0;

		public java.lang.Float next() {
			float result = value;
			value += 1.0;
			return result;
		}
	}

	public static class Double implements Generator {
		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.length
		print("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的内容赋值给i
		print("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/2
		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 = [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));// 长度不一样 所以为false
		int[] a1 = new int[10];
		int[] a2 = new int[10];
		print(Arrays.equals(a1, a2));// 初始值一样 长度一样 所以为true
		Arrays.fill(a1, 47);
		Arrays.fill(a2, 47);
		print(Arrays.equals(a1, a2));// 数值一样 长度一样 所以为true
		a2[3] = 11;
		print(Arrays.equals(a1, a2));// 其中一个数值不等  所以为false
		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));//string的比较是先比较地址 再比较字符串中的每个字符 这里虽然地址不同 但是值相同 返回true
		
		ComparingArrays[] 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 {
	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 generator() {
		return new Generator() {
			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 {
	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 这种方式适用于对象的查找
我们应该优先使用容器而不是数组 在容器引入泛型之后 数组的优势几乎荡然无存,除非发现性能问题,才会使用数组,而这种情况也是微乎其微的。

你可能感兴趣的:(java)