一、数组的简介
1.数组,是一种比较重要的数据结构,是用来存储一堆类型相同并且是有序的数据的容器(集合)。我们可以通过数组名以及一个不会越界的下标值(索引)来访问其中的元素。
2.数组,没有固定的类名,每一个数组都是对象。(基本数据类型的数据,称为值,不是对象)
特点:1. 数组是一个固定长度的容器,长度一旦固定,将不能够改变。
2. 数组的长度,代表了数组中能够存储多少个元素,类似于容器的容量
3. 元素,即存储在数组中的每一个数据,称为是数组的元素。
二、数组的实例化
在定义一个数组时,要使用[],可以理解为要存储一堆数据。 1.使用new的两种方式 第一种方式:new+直接初始化具体元素 第二种方式:new+长度 2. 静态初始化 直接使用{}进行初始化数组元素 数据类型[] 变量 = {元素1,元素2,.....,元素n}
注意:静态初始化不能先声明,再初始化。
注意:规定数组长度时,其实本质上是有长度个默认元素。
public class _01ArrayDemo {
public static void main(String[] args) {
//new+直接初始化具体元素
String[] names = new String[]{"小明","小红","小强","张三","李四"};
//new+长度: 注意,其实是有长度个默认元素
int[] nums = new int[5];//byte,short,int,long对应的默认元素是0
System.out.println(Arrays.toString(nums));
double[] a = new double[5];//double,float对应的默认元素是0.0
System.out.println(Arrays.toString(a));
char[] chars = new char[5];//char 对应的默认元素 \u0000
System.out.println(Arrays.toString(chars));
boolean[] bools = new boolean[5];
//boolean 对应的默认元素 false
System.out.println(Arrays.toString(bools));
String[] adds = new String[5]; //引用类型 对应的默认元素是null
System.out.println(Arrays.toString(adds));
//使用静态初始化的方式,实例化一个数组,注意:该方式不能先声明再初始化
int[] numbers = {1,2,3,4,5};
}
}
三、数组的元素访问
3.1 如何访问数组中的元素
数组实例化后,我们就可以访问数组中的的元素了。
1. 通过下标访问: 下标就是元素对应的索引值。 下标从0开始,最后一个元素下标为length-1。
2. 数组的长度: 变量名,length 。比如:name.length。
注意:length后面没有小括号!!!
3. 如何通过下标访问: 变量名[index]
public class _02ArrayDemo {
public static void main(String[] args) {
int[] ages = new int[]{20,18,19,20,19,30};
//获取ages中的第一个元素
int first = ages[0];
System.out.println("first: " + first);
//获取ages中的第四个元素
int four = ages[3];
System.out.println("fourth: " + four);
//打印ages的长度
System.out.println("长度"+ages.length);
//直接打印ages中的最后一个元素
System.out.println("最后一个元素:"+ages[ages.length - 1]);
//将年龄39存入到第二个位置
ages[1] = 39;
//将年龄50存入到最后一个位置
ages[ages.length - 1] = 50;
System.out.println(Arrays.toString(ages));
//创建一个具有5个长度的long类型数组
long[] ns = new long[5];
//将数字10,20,30,40,50分别存入。
ns[0] = 10;
ns[1] = 20;
ns[2] = 30;
ns[3] = 40;
ns[4] = 50;
System.out.println(Arrays.toString(ns));
//将数字1~10存入到int类型的数组scores里面。
int[] scores = new int[10];
for (int i = 0; i < scores.length; i++) {
scores[i]=i+1;
}
System.out.println(Arrays.toString(scores));
}
}
first: 20
fourth: 20
长度6
最后一个元素:30
[20, 39, 19, 20, 19, 50]
[10, 20, 30, 40, 50]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
3.2 常见的访问异常
(1)数组下标越界异常: 1. 什么时候发生的? 在运行期间发生的。 2. 怎么发生的? 当输入的下标大于等于数组的长度或者是小于0时发生的。 3.下标越界异常是运行时的异常,如果不做任何处理操作,那么jvm会暴力终止程序的运行。 (2)空指针异常:NullPointerException 1. 什么时候发生的? 在运行期间发生的。 2. 如何发生的? 使用null去访问各种方法或者属性。 比如:null.length()
public class _03ArrayDemo {
public static void main(String[] args) {
int[] nums = new int[]{1,3,2,4,5};
int e1 = nums[5];
System.out.println(e1);
int e2 = nums[nums.length+10];
System.out.println(e2);
//上述都属于下标越界异常
String[] names = { "小明","michael",null,""};
//打印每个元素的字符长度
for (int i = 0; i < names.length; i++) {
//处理null的情况
if (names[i] == null) {
continue;
}
System.out.println(names[i].length());
}
}
}
四、 数组的常见操作
4.1 遍历数组
遍历就是依次获取数组中的每一个元素。
(1)使用经典for循环,通过下标进行遍历。
(2) 使用foreach循环,也叫增强for循环。底层使用的是迭代器。
for(元素类型 变量名:数组|集合|枚举){
}
两者的对比:
-增强for循环中,没有下标的概念。 -增强for循环中,不能对数组中的元素进行改动。 -增强for循环比遍历下标的执行效率要高。
public class _04ArrayDemo {
public static void main(String[] args) {
int[] nums = new int[5];
for (int i = 0; i < nums.length; i++) {
nums[i] = (i+1)*10;
}
//直接打印数组的变量
System.out.println("数组变量:"+nums);//直接打印数组名得到的是类全名+@+内存地址的16进制数字
//调用Array.toString();
System.out.println("数组字符串:"+ Arrays.toString(nums));
//使用经典for循环,通过下标进行遍历
for (int i = 0; i < nums.length; i++) {
//i充当下标
System.out.println(nums[i]);
}
//使用foreach循环遍历上面的数组nums
System.out.println("----------增强for循环------------");
for(int n:nums){
System.out.println(n);
}
}
}
数组变量:[I@4554617c
数组字符串:[10, 20, 30, 40, 50]
10
20
30
40
50
----------增强for循环------------
10
20
30
40
50
4.2 元素排序
4.2.1 选择排序
原理(升序): 第一轮,拿0索引处的元素与后面的元素一一作比较,满足条件就交换,每次比较后都保证0索引处是较小值。 一轮结束,0索引处,就是最小值。 第二轮,拿1索引处的元素与后面的元素一一作比较,满足条件就交换,每次比较后都保证1索引处是较小值。一轮结束,1索引处,就是第二最小值。 每轮依次比较下去。 比较的轮数:元素个数-1 通过分析: 轮数是由外层循环控制的,每一轮的比较由内层循环控制。
public class _05ArrayDemo {
public static void main(String[] args) {
int[] nums = {6, 5, 3, 2, 4, 1};
//控制轮数
for (int i = 0; i < nums.length - 1; i++) {
//控制着每轮的比较
for (int j = i + 1; j < nums.length; j++) {
//nums[i]: 就是每轮要判断是否是最小元素的位置。
//nums[j}: 就是依次要比较的后续元素
if (nums[i] > nums[j]) {
//定义一个临时变量,保存i处的元素
int temp = nums[i];
//将j处的元素存入到i处
nums[i] = nums[j];
//将临时变量里面原i处二点元素,放入到j处
nums[j] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
}
}
[1, 2, 3, 4, 5, 6]
4.2.2 插入排序
原理(升序): 将一个数组的第一个元素看成是有序的。然后拿第二个元素与前面的元素从左到右作比较。 如果该值小于等于某一个元素,则进行插入。该位置处及其以后的有序元素都要向后移一位。 一共需要比较length-1轮。
(1)
public class _06ArrayDemo {
public static void main(String[] args) {
int[] nums = {4,6,1,3,2,7};
//分别拿nums[1]到nums[length-1]
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] < nums[j]) {
//向后移动然后插入
int temp = nums[i];
move(nums, j, i);
nums[j] = temp;
break;
}
}
}
System.out.println(Arrays.toString(nums));
}
/**
*
* @param arr [....1,4,6 3]
* @param min j i
* @param max
*/
public static void move(int[] arr, int min, int max) {
for (int i = max; i > min; i--) {
arr[i] = arr[i - 1];
}
}
}
运行过程: 原数组: 4 6 3 1 2 7 第一轮: 4 | 6 3 1 2 7 6和4比较,不需要交换 第二轮: 4 6 | 3 1 2 7 3和4作比较。需要插入 3存起来,每个元素向后移动 结果:3 4 6 | 1 2 7 第三轮: 需要插入, 1存起来,移动元素 结果:1 3 4 6 | 2 7 第四轮: 需要插入,2存起来,移动元素 结果: 1 2 3 4 6 | 7 第五次: 不需要插入
最终排序结果:
[1, 2, 3, 4, 6, 7]
(2)上述排序第二种方式
public class _07ArrayDemo {
public static void main(String[] args) {
int[] nums = {6,2,3,4,1,7};
for (int i = 1; i < nums.length; i++){
int temp = nums[i];
for(int j = i-1; j >= 0; j--) {
if(nums[i] > nums[j]) {
break;
}else {
nums[j+1]=nums[j];
}
nums[j]=temp;
}
}
System.out.println(Arrays.toString(nums));
}
}
4.2.3 冒泡排序
原理:从左到右,紧挨着的两个元素进行比较,满足条件就进行交换。比较length-1轮。 数组里有6个元素: 第一轮: 能找到最大值,冒泡到最右边。 比较5次 第二轮: 第二大元素冒泡到倒数第二个为止。 比较4次 .......... 第五轮: 第五大元素冒泡到正数的第二个为止。 最后一个数不再需要比较。 注意:每一轮比较时,都是从最左边的两个元素开始的。
public class _08ArrayDemo {
public static void main(String[] args) {
int[] nums = {6,2,4,7,1,5};
//外层循环控制的是轮数,轮数是length-1轮
for (int i = 0; i < nums.length-1; i++) {
//内层是控制着每轮如何比较,每次都要从左边开始比较,因此j从0开始
for (int j = 0; j < nums.length-1-i; j++) {
//如果前面的大于后面的,就进行交换操作
if(nums[j]>nums[j+1]){
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
}
}
[1, 2, 4, 5, 6, 7]
4.3 元素查找
(1)顺序查找
原理: 通过遍历数组,用数组的每一个元素依次和要查询的元素进行比较,如果相同,返回这个下标。
public class _09ArrayDemo {
public static void main(String[] args) {
int[] nums = {100,23,48,56,10,78};
//需求: 查找数组中是否有56,如果有,返回其坐标,如果没有返回-1.
int index = searchElement(nums, 56);
System.out.println(index);
}
//需求: 查找数组int类型的数组arr中是否有元素n,如果有,返回其坐标,如果没有返回-1.
public static int searchElement(int[] arr,int n) {
int index = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == n) {
index = i;
break;
}
}
return index;
}
}
运行结果:3。
(2)二分查找法
使用二分查找法的前提是,数组必须是排好序的。
下图代码是一个使用二分查找法,从int类型的数组arr中找元素element的方法。
找到,返回其坐标,没找到,返回-1。
public class _10ArrayDemo {
public static void main(String[] args) {
int[] nums = {1,4,6,7,9,10};
int index= binarySearch(nums,7);
System.out.println(index);
}
public static int binarySearch(int[] arr, int element) {
int min = 0,max = arr.length-1;
//min<=max时,表示还没有找到该元素,min=max时是最后一次查找
while (min <= max) {
//找到中间的元素下标
int mid = (min+max)/2;
if (arr[mid] == element) {
//如果mid位置上的元素就是我们要找的,就返回下标
return mid;
}else if (arr[mid] < element) {
//表明要查找的元素在中间值元素的右侧
min = mid+1;//将min设置为中见下标+1,然后重新循环
}else{//表示要查找的元素,在中间值的左侧
max = mid-1;//将max设置为中见下标-1,然后重新循环
}
}
//循环结束都没有遇到return,说明没有找到,就返回-1.
return -1;
}
}
运行结果:3。
五、数组工具类的应用
在Java中,Arrays是一个提供了各种数组操作的工具类。
1. toString():将数组转换为字符串形式。 "["+元素1+","+元素2+","+.....+"]"
2. binarySearch(数组名,要查找的元素):在已排序的数组中查找指定元素的索引。
3. fill(数组名,所有元素的指定值):将数组的所有元素都设置为指定值。
4. sort(数组):对数组进行排序。
5. copyOf():将一个数组的部分或全部元素复制到一个新数组中。
注意:上述的方法直接使用Arrays.调用。
public class _11ArrayDemo {
public static void main(String[] args) {
int[] nums = {1,2,3,4,5};
String info = Arrays.toString(nums);
System.out.println(info);//[1,2,3,4,5]字符串形式
System.out.println(Arrays.toString(nums));//[1,2,3,4,5]字符串形式
//工具类里的二分查找法,必须要求数组升序排序
int index = Arrays.binarySearch(nums, 4);
System.out.println(index);
//使用指定元素,填满整个数组
Arrays.fill(nums, 100);
System.out.println(Arrays.toString(nums));
//Arrays.sort(数组名):只能对已经提前设置好排序规则的类的数组进行排序。
int[] nums2 = {2,3,4,1,5};
Arrays.sort(nums2);
System.out.println(Arrays.toString(nums2));
//扩容:将原数组的所有元素都拷贝到新数组的最前面,然后多余的位置是默认值。注意:返回的是一个新数组。
int[] nums3 = Arrays.copyOf(nums2,10);//[1,2,3,4,5,0,0,0,0,0]
System.out.println(Arrays.toString(nums3));
//指定的长度一样,因此可以理解为,完全拷贝,新数组和原数组一模一样。
int[] nums4 = Arrays.copyOf(nums2,nums.length);
System.out.println(Arrays.toString(nums4));//[1,2,3,4,5]
//指定的长度小于原数组的长度,可以理解为部分拷贝,注意是从头开始拷贝。
int[] nums5 = Arrays.copyOf(nums2,3);//[1,2,3]
System.out.println(Arrays.toString(nums5));
}
}
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
3
[100, 100, 100, 100, 100]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
[1, 2, 3, 4, 5]
[1, 2, 3]
六、二维数组
数组中嵌套数组,数组中的元素,是一个小小的数组。
int[][] array = new int[3][];
array[0] = new int[4];
array[0][0] = 10;