数组
一、概念
1、什么是数组
数组(Array)是有序的元素序列。若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。
2、特点
-
数组是相同数据类型的元素的集合。
-
数组中的各元素的存储是有先后顺序的,它们在内存中按照这个先后顺序连续存放在一起。
-
数组元素用整个数组的名字和它自己在数组中的顺序位置来表示。例如,a[0]表示名字为a的数组中的第一个元素,a[1]代表数组a的第二个元素,以此类推。
3、存储形式
堆内存用来存放由new运算符创建的对象和数组,在堆中分配的内存,由java虚拟机的自动垃圾回收器来管理。在堆中创建了一个数组或对象后,同时还在栈内存中定义一个特殊的变量。让栈内存中的这个变量的取值等于数组或者对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,引用变量实际上保存的是数组或对象在堆内存中的地址(也称为对象的句柄),以后就可以在程序中使用栈的引用变量来访问堆中的数组或对象。
二、数组的使用
1、数组的创建
语法:
/*格式1:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
示例:
*/
int[] arr = new int[5];
/*
格式2:
元素类型[] 数组名 = new 元素类型[]{元素,元素,……};
*/
int[] arr = new int[]{3,5,1,7};
int[] arr = {3,5,1,7};
注:数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arr.length-1。且给数组分配空间时,必须指定数组能够存储的元素个数来确定数组大小。创建数组之后不能修改数组的大小。可以使用length 属性获取数组的大小。
例:
public static void creatArray(){
// 数组大小
int size = 10;
// 定义数组
double[] myList = new double[size];
for (int i = 0;i < 10;i++){
myList[i] = i;
}
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < size; i++) {
System.out.print(myList[i]+" ");
total += myList[i];
}
System.out.println("");
System.out.println("总和为: " + total);
}
图解:
2、数组的遍历
代码演示
//方式一:for循环
public static void listFor(){
int[] arrs = {1,3,4,5,6,6,7};
for (int i = 0; i < arrs.length; i++) {
System.out.print(arrs[i]+" ");
}
}
//方式二:for-each
public static void listFor(){
int[] arrs = {1,3,4,5,6,6,7};
for (int arr : arrs) {
System.out.print(arr+" ");
}
}
结果:
3、数组常见异常
-
NullPointerException 空指针异常
原因: 引用类型变量没有指向任何对象,而访问了对象的属性或者是调用了对象的方法。 -
ArrayIndexOutOfBoundsException 索引值越界。
原因:访问了不存在的索引值。
4、数组内存分析
三、Arrays常用方法
Arrays具有以下功能:
- 给数组赋值:通过 fill 方法。
- 对数组排序:通过 sort 方法,按升序。
- 比较数组:通过 equals 方法比较数组中元素值是否相等。
- 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
1、fill(int[] a, int val)
-
作用:
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
-
使用
public static void fill(){ int[] arrs = {1,3,4,5,6,6,7}; Arrays.fill(arrs, 2); System.out.println(Arrays.toString(arrs)); }
结果:
-
Jdk分析
//使用val对a数组进行数据填充 public static void fill(long[] a, long val) { fill(a, 0, a.length, val); } //使用val对a数组从fromIndex(包含)至toIndex(不包含)位置进行数据填充 public static void fill(long[] a, int fromIndex, int toIndex, long val) { rangeCheck(a.length, fromIndex, toIndex); for (int i=fromIndex; i<toIndex; i++) a[i] = val; }
-
2、sort(Object[] a)
-
作用:
对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
-
使用:
public static void sort(){ int[] arrs = {1,5,4,6,3,6,2}; System.out.println(Arrays.toString(arrs)); Arrays.sort(arrs); System.out.println(Arrays.toString(arrs)); }
结果:
-
Jdk源码
//对数组a进行排序 public static void sort(long[] a) { sort1(a, 0, a.length); } //对数组a中的从fromIndex(包含)至toIndex(不包含)的值进行排序 public static void sort(long[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); sort1(a, fromIndex, toIndex-fromIndex); } /** 对基本类型数组的排序有以上两种方法,这里只摘出了long类型的。sort1方法篇幅原因没有摘出来,在sort1方法中使用的是经过调优的快速排序算法(tuned quicksort)。 **/ .......... .......... .......... //对对象类型进行排序 public static void sort(Object[] a) { Object[] aux = (Object[])a.clone(); mergeSort(aux, a, 0, a.length, 0); } //对对象a中的从fromIndex(包含)至toIndex(不包含)的值进行排序 public static void sort(Object[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); Object[] aux = copyOfRange(a, fromIndex, toIndex); mergeSort(aux, a, fromIndex, toIndex, -fromIndex); } /** 对对象类型数组的排序有以上两种方法,在mergeSort方法中使用的是经过修改的归并排序算法(modified mergesort)。 **/
-
3、equals(long[] a, long[] a2)
-
作用:
如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
-
使用:
public static void equal(){ int[] arrs1 = {1,5,4,6,3,6,2}; int[] arrs2 = {1,5,4,6,3,6,2}; int[] arrs3 = {1,2,3,4,5,6,2}; System.out.println(Arrays.equals(arrs1, arrs2)); System.out.println(Arrays.equals(arrs1, arrs3)); }
结果:
-
Jdk源码
//比较基本类型数组是否相等 public static boolean equals(long[] a, long[] 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++) if (a[i] != a2[i]) return false; /** 对于double类型,使用的是: if (Double.doubleToLongBits(a[i])!=Double.doubleToLongBits(a2[i])) return false; 对于float类型,使用的是: if (Float.floatToIntBits(a[i])!=Float.floatToIntBits(a2[i])) return false; 这样做是为了精确比较。 **/ return true; } ..... ..... ..... //比较Object类型数组是否相等 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; } ..... ..... ..... //深度比较两个数组是否相等 public static boolean deepEquals(Object[] a1, Object[] a2) { if (a1 == a2) return true; if (a1 == null || a2==null) return false; int length = a1.length; if (a2.length != length) return false; for (int i = 0; i < length; i++) { Object e1 = a1[i]; Object e2 = a2[i]; if (e1 == e2) continue; if (e1 == null) return false; // Figure out whether the two elements are equal boolean eq; if (e1 instanceof Object[] && e2 instanceof Object[]) eq = deepEquals ((Object[]) e1, (Object[]) e2); else if (e1 instanceof byte[] && e2 instanceof byte[]) eq = equals((byte[]) e1, (byte[]) e2); else if (e1 instanceof short[] && e2 instanceof short[]) eq = equals((short[]) e1, (short[]) e2); else if (e1 instanceof int[] && e2 instanceof int[]) eq = equals((int[]) e1, (int[]) e2); else if (e1 instanceof long[] && e2 instanceof long[]) eq = equals((long[]) e1, (long[]) e2); else if (e1 instanceof char[] && e2 instanceof char[]) eq = equals((char[]) e1, (char[]) e2); else if (e1 instanceof float[] && e2 instanceof float[]) eq = equals((float[]) e1, (float[]) e2); else if (e1 instanceof double[] && e2 instanceof double[]) eq = equals((double[]) e1, (double[]) e2); else if (e1 instanceof boolean[] && e2 instanceof boolean[]) eq = equals((boolean[]) e1, (boolean[]) e2); else eq = e1.equals(e2); if (!eq) return false; } return true; }
4、binarySearch(Object[] a, Object key)
-
作用:
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。
-
使用:
public static void binarySearch(){ int[] arrs1 = {1,5,4,6,3,6,2}; Arrays.sort(arrs1); System.out.println(Arrays.binarySearch(arrs1, 4)); }
结果:
-
Jdk源码
/** 对数组中元素的查找有以上两种方法,在binarySearch0方法中使用的是二分查找法。并且对基本类型和对象类型的数组查找是同样的操作。 **/ public static int binarySearch(long[] a, long key) { return binarySearch0(a, 0, a.length, key); } public static int binarySearch(long[] a, int fromIndex, int toIndex, long key) { rangeCheck(a.length, fromIndex, toIndex); return binarySearch0(a, fromIndex, toIndex, key); }
-
注:参考博客