增强的for循环
JDK1.5提供了增强的for循环功能,可以简化遍历数组的操作,但是不能进行和索引相关的操作,遍历数组过程中不能修改数组中某元素的值。功能其实没有增加。
数组操作的常见异常主要有:NullPointerException:空指针异常
ArrayIndexOutOfBoundsException:数组索引越界异常(超过下界或者上界)
public class TestArray2{ public static void main(String [] args){ //数组静态初始化 double [] scoreArr = {90.5,80,45,78,30}; //修改数组的各个元素的值(提5分) for(int i=0;i scoreArr[i] = scoreArr[i]+5; } for(double score :scoreArr){//赋给一个新的变量score,值和数组元素相同 score = score +5;//修改的是新的变量score,和数组元素无关 } //输出数组的各个元素的值(遍历) for(int i=0;i System.out.println("第"+(i+1)+"个元素"+scoreArr[i]); } for(double score : scoreArr){ System.out.println(score); } //数组引用的赋值 double [] scoreArr2 = scoreArr; scoreArr[0] = 100; scoreArr2[4] = 100; for(double score : scoreArr){ System.out.println(score); } System.out.println(); for(double score : scoreArr2){ System.out.println(score); } //System.out.println(scoreArr2[-1]); double [] scoreArr3 = null; //scoreArr3 = new double[10]; //scoreArr3 = scoreArr2; System.out.println(scoreArr3[0]); }}
理解数组引用的赋值:scoreArr2 = scoreArr; 两个数组引用指向了堆内存中相同的数组数据。
数组应用
1、查询数组元素
可以查询指定索引的元素的内容,直接按照索引定位即可; 可以按照指定内容元素的索引,需要逐个比较,直到找到为止,或者比较到数组的末尾也没有找到。public class TestArray3{ public static void main(String [] args){ //使用数组存储10个学生的分数 int [] scoreArr = {75,87,56,45,89,100,76,34,89,97}; //获取第8个学生的分数 1 8 int position = 2; int score = scoreArr[position-1]; System.out.println("第"+position+"个学生的分数是:"+score); //获取分数的76的学生的索引(第一个) int index = -1; int elem = 101; for(int i=0;i if(elem == scoreArr[i]){ index = i; break; } } if(index == -1){ System.out.println("数组中不存在该值:"+elem); }else{ System.out.println(elem+"在数组中的索引:"+index); } }}
总结1:数组按照索引查询数据,效率最高;不管索引是哪个,花费的时间是一样的;
原理:分配连续的空间,且每个元素的空间大小是相同的,所以指定索引的元素位置=数组的起始位置+每个元素的大小*索引,无需进行逐个比较。
总结2:数组按照内容查询数据效率低下;
一般需要从第一个元素逐次比较,直到找到位置;或者比较到数组的最后一个元素也没有找到,则确认无该元素。 如果数组的数据是大小有序的,可以通过折半查找的方式来提高查询效率。2、删除数组元素
删除指定索引的元素public class TestArray4{ public static void main(String [] args){ //1.使用数组存储分数 int [] scoreArr = {75,87,56,45,89,100,76,34,89,97}; //2.删除之前输出 System.out.println("删除前"); for(int score :scoreArr){ System.out.print(score+"\t"); } //3.删除索引为4的元素 int index = 4; //3.1从第i个元素开始,将后一个元素前移一个位置 for(int i = index; i scoreArr[i]=scoreArr[i+1]; } //3.2最后一个元素置为0 scoreArr[scoreArr.length-1] = 0; //4.删除之后输出 System.out.println("\n删除后"); for(int score :scoreArr){ System.out.print(score+"\t"); } }}
总结1:数组的优点:
一个数组可以存储多个元素
按照索引查询元素效率高
总结2:数组的缺点:
按照内容查询元素,效率低下
进行删除和添加时候需要大量的移动元素,效率低下;
长度固定
可以提取删除数组元素的方法,直接调用该方法即可实现删除。注意:这可是第一次使用数组做方法的形参。
public class TestArray5{ public static void main(String [] args){ //使用数组存储分数 int [] scoreArr = {75,87,56,45,89,100,76,34,89,97}; //删除之前输出 System.out.println("删除前"); for(int score :scoreArr){ System.out.print(score+"\t"); } //3.删除索引为4的元素 int index = 4; deleteElem(scoreArr,index); //删除之后输出 System.out.println("\n删除后"); for(int score :scoreArr){ System.out.print(score+"\t"); } } public static void deleteElem(int [] arr,int index){ //3.1从第index个元素开始,将后一个元素前移一个位置 for(int i = index; i arr[i]=arr[i+1]; } //3.2最后一个元素置为0 arr[arr.length-1] = 0; }}
使用数组作为方法的形参,这还是第一次。内存分配图如图所示:
问题:scoreArr和arr数组有联系和区别
联系:
scoreArr是实参,arr是形参
方法调用时将实参付给形参 arr = scoreArr;
导致arr和scoreArr都指向内存中同一个数组
在deleteElem中操作arr就相当于在main中操作scoreArr
区别:
作用范围不同且互不冲突
scoreArr在main方法中定义的变量,作用范围是main
arr在deleteElem方法中定义的变量,作用范围是deleteElem
3、添加数组元素
功能:在数组的索引为i的位置添加一个新的值value。
实现思路和删除类似,需要大量的移动元素。需要从末尾开始,将后面元素都后移一个位置,空出第i个位置来,再放入要添加的元素值value。
public class TestArray6 { public static void main(String [] args){ //使用数组存储分数 int [] scoreArr = {75,87,56,45,89,100,76,34,0,0}; //添加之前输出 System.out.println("添加前"); for(int score :scoreArr){ System.out.print(score+"\t"); } //3.在索引为4的位置添加90 int index = 4; int value = 90; insertElem(scoreArr,index,value); //添加之后输出 System.out.println("\n添加后"); for(int score :scoreArr){ System.out.print(score+"\t"); } } public static void insertElem(int [] arr,int index,int value){ //从最后一个元素开始,将前一个元素后移一个位置 for(int i = arr.length-1; i>index;i--){ arr[i]=arr[i-1]; } //第index的元素赋值为value arr[index] = value; }}
数组的更多工具
1、Arrays工具类
JDK提供的java.util.Arrays工具类,包含了常用的数组操作,方便我们日常开发。Arrays类包含了:排序、查找、填充、打印内容等常见的操作。public class TestArray7 { public static void main(String[] args) { //定义一个数组 int[] scoreArr = {75, 87, 56, 45, 89, 100, 76, 34, 89, 97}; //遍历数组 System.out.println(Arrays.toString(scoreArr)); //数组排序 Arrays.sort(scoreArr); System.out.println(Arrays.toString(scoreArr)); //查询数据 int index = Arrays.binarySearch(scoreArr, 89); System.out.println(index); //数组的填充 // Arrays.fill(scoreArr,10); Arrays.fill(scoreArr, 3, 8, 10); System.out.println(Arrays.toString(scoreArr)); //数组复制 /* int [] scoreArr2 = new int[10]; for(int i=0;i scoreArr2[i] = scoreArr[i]; }*/ int[] scoreArr2 = Arrays.copyOf(scoreArr, scoreArr.length); //int [] scoreArr2 = Arrays.copyOf(scoreArr,20); //int [] scoreArr2 = Arrays.copyOf(scoreArr,5); System.out.println(Arrays.toString(scoreArr2)); //数组比较 boolean flag = Arrays.equals(scoreArr, scoreArr2); System.out.println(flag); }}
注意1:Arrays.binarySearch(arr,elem );是二分查找,要求数组必须有序。
注意2:在JDK8增加parallelSort()方法,为并发排序方法,适合数据量大的情况。
注意3:JDK8后增加了和函数式接口、lamda表达式,流式编程有关方法,暂时无法讲解。
2、数组拷贝
Arrays.copyOf()的底层使用了System类的arraycopy( )方法。
public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy;}
参数含义
public static native void arraycopy (Object src, //源数组 int srcPos, //源数组要复制的起始位置 Object dest,//目的数组 int destPos,//目的数组要复制到的起始位置 int length); //要复制的数组元素的数量public class TestArray8 { public static void main(String args[]) { String[] arr1 = {"阿里", "腾讯", "百度", "京东", "华为"}; System.out.println(Arrays.toString(arr1)); String[] arr2 = new String[10]; System.out.println(Arrays.toString(arr2)); System.arraycopy(arr1, 0, arr2, 0, arr1.length); //等价于如下语句,但是 System.arraycopy()效率更高 //for (int i = 0; i < arr1.length; i++) { arr2[i] = arr1[i]; } System.out.println(Arrays.toString(arr2)); Arrays.fill(arr2, null); System.arraycopy(arr1, 2, arr2, 4, 2); System.out.println(Arrays.toString(arr2)); }}
之前的删除操作可以使用System.arrayCopy()优化一下,提供效率。但是添加操作无法使用该方法优化,因为添加元素需要从后移动元素。
//删除操作System.arraycopy(scoreArr,index+1,scoreArr,index,scoreArr.length-1-index);scoreArr[scoreArr.length-1] = 0;
Arrays.copyOf()和System.arrayCopy()的区别
- Arrays.copyOf()需要一个新的数组,经常用于实现数组扩容。真正复制元素时使用的就是System.arrayCopy();
- System.arrayCopy()是一个native方法(Java本身无法实现,需要调用C/C++代码实现),效率高。可以是两个数组的复制,也可以是一个数组的元素的复制
3、可变参数
JDK1.5提供了定义方法时使用可变参数的功能,语法为格式为:参数类型...参数,允许实参可以是0个、1个、n个,甚至数组的形式。可以进步的减少方法重载的数量。public class TestArray9{ public static void main(String [] args){ System.out.println(add()); System.out.println(add(10)); System.out.println(add(10,20)); System.out.println(add(10,20,30)); System.out.println(add(10,20,30,40,50)); int [] numArr ={10,20,30,40,50}; System.out.println(add(numArr)); } public static int add(int ... numArr){ int sum = 0; for(int num :numArr){ sum += num; } return sum; }}
总结1:可变参数关键点
可变参数的好处:简单 方便 直观 减少方法重载的数量
可变参数只能做方法的形参
可变参数的实参可以是0个、1个、多个,也可以是一个数组
一旦定义了可变参数,就不能定义数组参数了
可变参数底层是一个数组,根据传递参数的个数不同,会创建出不同长度的数组,来存储这些参数传递的参数个数。在方法体中,可变参数就是通过数组来处理的
一个方法的可变参数只能有一个,必须是最后一个参数
总结2:可变参数和数组参数的区别和联系
联系
可变参数底层是一个数组,在方法体中可变参数是当做数组来处理的;
方法的实参都可以是数组
区别
个数不同
位置不同
实参不同