Think in Java第四版 读书笔记10 第16章 数组
数组和容器很像 但他们有一些差别
数组与容器的区别主要在效率和存储类型
效率:数组是简单的线性序列 使得数组的访问很快 但是数组长度固定,没有容器灵活, 容器的灵活是需要系统付出更多的开销的。从访问效率上看 数组更高
存储类型:在没有泛型之前 数组可以存储固定类型的元素 而容器只能存储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
*/// :~
数组标识符是一个引用,它指向堆中创建的一个真实对象 该对象保存指向其他对象的引用,该对象还有一个只读成员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
*/// :~
1.数组没有初始化之前 不能做任何事情
2.bool类型数组元素默认初始化 false 其他基本类型默认初始化为0(char默认初始化为’\u0000’)
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内容被修改
}
}
}
个人觉得还是不要直接返回数组比较好 因为如果每次返回都是原数组,那么其他任意地方都可能修改其内容,那要检测其内容就会变得尤其困难。
//多维数组的创建与输出
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]]
*///:~
无法直接创建泛型数组
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]);
}
} // /:~
介绍各种工具填充数组
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]
*/// :~
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中创建数组 略
Arrays有6个基本方法
equals判断数组是否相等(deep Equals用于多维数组)
fill为数组填充单一元素
sort数组排序
binarySearch对已经排序的数据进行二分查找
toString产生数组的字符串形式
hashCode返回数组的哈希值
另:Arrays.asList接受任意序列或数组 返回一个List
// 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]
*/// :~
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
*/// :~
数组中的元素实现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]
]
*/// :~
如果数组元素是基本数据类型或字符串类型 可以使用内置排序方法直接排序
例子:
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);
}
源码中可以看到 针对对象排序使用了归并排序
针对基本类型 如果继续跟踪代码可以看到使用的是二分排序
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 这种方式适用于对象的查找
我们应该优先使用容器而不是数组 在容器引入泛型之后 数组的优势几乎荡然无存,除非发现性能问题,才会使用数组,而这种情况也是微乎其微的。