16.1数组为什么特殊
在Java中数组是效率最高的存储和随机访问对象引用序列的方式,数组是一个线型程序。
数组和容器如果越界都会抛出RuntimException异常。
在泛型之前,其它容器类在处理对象时都会当作Object类型,数组之所以优于泛型之前的容器,创建一个数组时就限定了数组持有对象的类型,这意味着可以在编译器进行检查。
数组可以持有基本类型,泛型之前的容器则不能,但有了泛型和自动装箱,其它容器也可以持有基本类型数据,数组仅存的优点就是效率。
public class BerylliumSphere { public static long count; public final long id = count++; @Override public String toString() { return "BerylliumSphere [id=" + 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(); } System.out.println(Arrays.toString(spheres)); System.out.println(spheres[4]); //集合保存对象 List<BerylliumSphere> phereList = new ArrayList<BerylliumSphere>(); for (int i = 0; i < 5; i++) { phereList.add(new BerylliumSphere()); } System.out.println(phereList); System.out.println(phereList.get(4)); //数组保存基本类型 int[] integers = {1,2,3,4,5}; System.out.println(Arrays.toString(integers)); System.out.println(integers[4]); //集合保存基本类型 List<Integer> intList = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { intList.add(i); } intList.add(97); System.out.println(intList); System.out.println(intList.get(4)); } } /* Output: [BerylliumSphere [id=0], BerylliumSphere [id=1], BerylliumSphere [id=2], BerylliumSphere [id=3], BerylliumSphere [id=4], null, null, null, null, null] BerylliumSphere [id=4] [BerylliumSphere [id=5], BerylliumSphere [id=6], BerylliumSphere [id=7], BerylliumSphere [id=8], BerylliumSphere [id=9]] BerylliumSphere [id=9] [1, 2, 3, 4, 5] 5 [0, 1, 2, 3, 4, 97] 4 **/
16.2 数组是第一级对象
只读lengh是数组对象唯一可以访问的字段或方法,“[]”是访问数组的唯一方式。
对象数组保存的是引用,基本类型数组直接保存基本类型的值。
public class ArrayOptions { public static void main(String[] args) { BerylliumSphere[] b = new BerylliumSphere[5]; System.out.println(Arrays.toString(b)); System.out.println(b.length); } } /* Output: [null, null, null, null, null] 5 **/
数组b初始化为BerylliumSphere数组,但仍然可以通过length访问数组的大小,length只表示数组能够容纳多个元素,而不是实际保存元素的个数,这种小缺点使得无法知道数组b中确切的有多少个元素。
对象数组初始化时,其中所有的引用被初始化为null,所以检查其中的引用是否为null,就可以知道数组某个位置是否有对象。
int[] e; //The local variable e may not have been initialized System.out.println(e.length);
数组也是对象,为初始化的null对象不访问其对象或属性,编译器就会有错误。
16.3 返回一个数组
public class IceCream { private static Random random = new Random(47); private static final String[] FLAVORS = new String[]{"A","B","C","D","E","F","G","H","I","J","K"}; public static String[] flavorSet(int n){ if(n>FLAVORS.length) throw new IllegalArgumentException("Set too big"); String[] result = new String[n]; boolean[] picked = new boolean[FLAVORS.length];//判断是否重复 for (int i = 0; i < n; i++) { int index ; do { index = random.nextInt(FLAVORS.length); } while (picked[index]);//false:不重复的 true:重复的,会再次的循环 result[i] = FLAVORS[index]; picked[index] = true; } return result; } public static void main(String[] args) { System.out.println(Arrays.toString(flavorSet(3))); } }
16.4 多维数组
int[] [] a = {{1,2},{3,4},{5,6}}; System.out.println(Arrays.deepToString(a));
16.5 数组与泛型
class ClassParameter<T> { public T[] f(T[] arg) { return arg; } } class MethodParameter { public static <T> T[] f(T[] arg) { return arg; } } public class ParameterizedArrayType { public static void main(String[] args) { Integer[] arr = {1,2,3}; Integer[] a = new ClassParameter<Integer>().f(arr); Integer[] b = MethodParameter.f(arr); System.out.println(Arrays.toString(a)); System.out.println(Arrays.toString(b)); } }
这种方式虽可以是数组具有泛型特性,但泛型容器总是更好的选择。
public class ArrayOfGenericType<T> { T[] array; public ArrayOfGenericType(int size){ //array = new T[size];//Cannot create a generic array of T array = (T[]) new Object[size];//Type safety: Unchecked cast from Object[] to T[] } }
泛型在类或方法上很有效,但在类或方法内部擦除泛型会带来有问题。
16.6 创建测试数据
Arrays.fill()用同一个值填充各个位置,而针对对象而言,就是复制同一个引用进行填充。
public class FillingArrays { public static final Integer SIZE = 6; public static void main(String[] args) { int[] a1 = new int[SIZE]; Arrays.fill(a1, 1); System.out.println(Arrays.toString(a1)); String[] a2 = new String[SIZE]; Arrays.fill(a2, "a"); System.out.println(Arrays.toString(a2)); String[] a3 = new String[SIZE]; Arrays.fill(a3, 1,3,"c"); System.out.println(Arrays.toString(a3)); } }
P443 16.6.2
16.7 Arrays实用功能
数组的复制
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); System.out.println("i = "+Arrays.toString(i)); System.out.println("j = "+Arrays.toString(j)); System.arraycopy(i, 0, j, 0, i.length); System.out.println("j = "+Arrays.toString(j)); Integer[] x = new Integer[7]; Integer[] y = new Integer[10]; Arrays.fill(x, 47); Arrays.fill(y, 99); System.out.println("x = "+Arrays.toString(x)); System.out.println("y = "+Arrays.toString(y )); System.arraycopy(x, 0, y, 0, x.length); System.out.println("y = "+Arrays.toString(y)); System.arraycopy(i, 0, y, 0, i.length);// java.lang.ArrayStoreException } } /* 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] x = [47, 47, 47, 47, 47, 47, 47] y = [99, 99, 99, 99, 99, 99, 99, 99, 99, 99] y = [47, 47, 47, 47, 47, 47, 47, 99, 99, 99] Exception in thread "main" java.lang.ArrayStoreException at java.lang.System.arraycopy(Native Method) at rock.lee.c16.CopyingArrays.main(CopyingArrays.java:25) **/
复制对象数组,只是复制了对象的引用,而不是对象本身的拷贝,被称作“浅复制”。System.arraycopy()不会自动装箱和自动拆箱,所以两个数组成copy时必须具有相同类型,最后把int类型copy到Integer类型是不可以的。
数组的比较
public class ComparingArrays { public static void main(String[] args) { int[] a1 = new int[10]; int[] a2 = new int[10]; Arrays.fill(a1, 2); Arrays.fill(a2, 2); System.out.println(Arrays.equals(a1, a2));//true a2[2]= 1; System.out.println(Arrays.equals(a1, a2));//false String[] s1 = new String[2]; String[] s2 = new String[]{"a","a"}; Arrays.fill(s1, "a"); System.out.println(Arrays.equals(s1, s2));//true } }
数组相等的条件:1、元素个数相等 2、对应位置的元素相等
通过对每一元素使用equals()作为比较判断,基本类型是通过其包装类的equals(),如Integer.equals()。
数组元素的比较
数组的排序
在以排序的数组中查找