数组的定义
什么是数组?
数组是一种特殊的数据类型,这种数据类型用于存储一组数据类型相同的数据。简单来说,数组就是一个容器,用于存储一组数据,这组数据具有相同的数据类型。
数组中的每个数据称为数组的元素。
有如下需求:某幼儿园有一个小班,班里有10个小朋友,要记录每个小朋友的年龄,如何记录?
方法一:定义10个 int 类型变量,每个变量保存一个小朋友的年龄。
方法二:定义1个 int 类型数组,数组中保存10个小朋友的年龄。
数组具有2个特点:
1. 数组中的元素具有相同的数据类型。
2. 数组的容量是确定的。---创建数组的时候确定其容量。
注意:
数据类型分为:基本数据类型和引用类型。
1.基本数据类型: byte、short、int、long、float、double、char、boolean
2.引用数据类型:数组、类、接口
为什么要使用数组?
在开发中,数组使用非常频繁。例如:新闻App的新闻列表页面,就是一组新闻;电商项目要统计每天的订单情况,订单也是一组数据;购物网站的商品列表,也是一组数据...几乎所有的软件都有这种成组出现的数据。因此数组使用场景无处不在。
使用数组有以下原因:
1. 简化代码:数组能存储一组数据,因此可以将多个变量合为一个变量。
表示一组数据,可以定义多个变量,但是代码量大。使用数组的话,只需要一个变量就能存储一组数据。
2. 便于批量操作数据:数组和循环经常搭配使用,通过循环可以操作每一个数据。
例如:有一组订单,现在需要对订单按天进行统计销售额。可以使用一个循环,遍历每一个订单,属于同一天的订单进行求和。 如果每个订单都用一个变量保存的话,就没有办法使用循环进行操作。
如何定义数组?
数组的定义格式:
格式一: 数据类型[] 变量名
例如: int[] ages
含义:定义一个整型数组,数组的名字叫ages。
格式二: 数据类型 变量名[]
例如: int ages[]
含义:定义一个整型数组,数组的名字叫ages。
推荐使用格式一。1. 便于理解;2.很多程序员都在使用格式一,便于阅读彼此的代码
格式二是为了兼容C语言的写法,便于C程序员转型为Java程序员。
数组的初始化
变量定义的三要素:数据类型 、变量名、初始值。
数组是一种数据类型,在定义数组变量的时候,也要为其指定初始值。数组的初始值指的是数组中每个元素的初始值。
数组的初始化分为2种:动态初始化 和 静态初始化。
动态初始化
动态初始化:在初始化数组时,只指定数组长度,由系统为其分配初始值。
数组长度:数组所能容纳的元素的个数。
数组元素的默认初始值
动态初始化格式:数据类型[] 变量名 = new 数据类型[数组长度];
示例: int[] ages = new int[10];
上述代码定义了一个int类型的数组,数组名是ages,数组的元素个数是10,每个元素都是int类型,每个元素的初始值是0。
等号左边:
1. int 表示数组中的元素是int类型。
2. [] 表示这是一个数组。
3. ages是数组名称,即变量名。
等号右边:
1. new 为数组申请堆区内存空间。申请的内存空间是连续的,内存空间的大小取决于元素类型 和元素个数。
2. int 表示数组中的元素是int类型。
3. []表示是一个数组,[10]表示数组能容纳10个数据。
4. 因为是动态初始化,系统为每个int元素分配的初始值是0。
静态初始化
静态初始化:初始化数组时,人为指定每个元素的值。
格式一: 数据类型[] 变量名 = new 数据类型[]{数据1,数据2,数据3,...};
格式一示例: int[] ages = new int[]{3, 4, 4, 3, 2, 4, 3, 4, 3, 3};
上述代码定义了一个int数组,数组名是ages,数组中包含10个int数据。它们的初始值不再是系统默认给的0,而是我们人为指定的初始值。
等号左边:
1. int 表示数据元素是int类型。
2. [] 表示这是一个数组。
3. ages是数组名,即变量名。
等号右边:
1. new 为数组申请堆内存空间。申请的内存空间是连续的,内存空间的大小取决于元素类型和元素个数。
2. int 表示数组中的元素是 int类型。
3. [] 表示这是一个数组。-----注意不要写元素个数。
4. {3, 4, 4, 3, 2, 4, 3, 4, 3, 3} 表示数组中每个元素的初始值。大括号中写了几个值,数组的元素个数就是几。
格式二:-----格式二是格式1的简化格式,通常使用这种格式。
数据类型[] 变量名 = {数据1, 数据2, 数据3,...};
格式二示例: int[] ages = {3, 4, 4, 3, 2, 4, 3, 4, 3, 3};
格式二定义的数组和格式一含义一样,只是格式一的简化形式。
数组访问
数组访问包括:数组的访问、数组元素的访问。
数组的访问
数组在内存中是一段连续的内存区域。
数组名是一个变量,但是它不存储具体数据,存储的是这段连续内存区域的起始地址(也叫首地址)。
数组名代表的是整个数组,不代表数组中的元素。
数组变量的访问方式:数组名
在打印数组变量的时候,会打印出数组所存储的内存地址。
数组元素的访问
格式:数组名[索引]
索引指的是数据的序号(编号),通常也称为数组的下标。在Java中数组下标是从0开始的。即第1个数据下标为0,第2个数据下标为1,第3个数据下标为2,...
数组名[索引] 等同于一个变量,是一种特殊的变量名。
索引的最小值是:0,索引的最大值是:元素个数 - 1
数组元素的访问包括:给数组元素的赋值、使用数组元素的值。
给数组元素赋值
public static void main(String[] args) {
int[] ages = {3, 4, 3, 2, 5};
System.out.println(ages[0]);
ages[0] = 7;//此处将ages[0]的值赋值为7,会覆盖原有的3
System.out.println(ages[0]);
}
使用数组元素的值
public static void main(String[] args) {
int[] ages = {3, 4, 3, 2, 5};
System.out.println(ages[0]);
ages[0] = 7;//此处将ages[0]的值赋值为7
System.out.println(ages[0]);
int num = ages[1];//将ages[1]赋值给变量num
int sum = ages[2] + ages[3];//将ages[2]于ages[3]的和赋值给sum
System.out.println(num);
System.out.println(sum);
}
数组访问总结
1. 数组名代表的是整个数组,存储的是数组的起始地址。
2. 数组元素是数组中真正的数据,数组元素的访问方式是 数组名[索引]
3. 索引的最小值是:0,最大值是:元素个数-1
数组的内存分配
栈区和堆区
Java语言对内存做了若干个分区,最为重要的2个分区是:堆区和栈区。
栈区:用于存放局部变量的内存区域。
局部变量:方法内定义的变量,包括方法的参数。
栈区由系统管理,系统为每个变量分配一个区域。以栈的方式管理变量的生命周期。
堆区:唯一一个程序员可以操作和使用的内存区域。
堆区必须通过new来开辟空间。
程序员只负责开辟和使用堆区空间,Java的垃圾回收机制会在堆区内存不再使用的时候,回收开辟的区域。
数组的内存
public static void main(String[] args) {
//array变量是局部变量,array变量存放在栈区,有系统管理array变量的生命周期。
//虽然array自己存放在栈区,但是array变量的值 是数组的起始地址,存的是new新开辟的12个字节的首地址。
int[] array = new int[3];
System.out.println(array);//此处打印的是数组的起始地址(堆区)
System.out.println(array[0]);// 0
System.out.println(array[1]);// 0
System.out.println(array[2]);// 0
array[0] = 20;//数组元素的赋值
array[2] = 10;//数组元素的赋值
array[1] = array[0] + array[2];//数组元素的赋值
System.out.println(array[0]);// 20
System.out.println(array[1]);// 30
System.out.println(array[2]);// 10
}
下面是创建数组array的内存分配图:
对于 int[] array = new int[3];这行代码,可以细分为4个步骤:
1. 定义局部变量array,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] array
2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。
3. 系统为数组的3个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[3]
4. 将数组的首地址赋值给变量array,因此array的值是地址15db9742
因此执行下面4行代码时
System.out.println(array);//此处打印的是数组的起始地址(堆区),即15db9742
System.out.println(array[0]);// 0
System.out.println(array[1]);// 0
System.out.println(array[2]);// 0
打印的结果分别是:
[I@15db9742
0
0
0
下面6行代码是给数组元素赋值,并打印元素的值。
array[0] = 20;//数组元素的赋值
array[2] = 10;//数组元素的赋值
array[1] = array[0] + array[2];//数组元素的赋值
System.out.println(array[0]);// 20
System.out.println(array[1]);// 30
System.out.println(array[2]);// 10
下面是数组元素赋值的内存示意图:
1. array[0] = 20; 这是一行赋值语句,把数据20赋值给数组的第1个元素,第1个元素就是数组下标为0的元素。赋值之后,元素的值由0变成了20。数组名[索引]可以看成是一个变量。
2. array[2] = 10;这行也是一条赋值语句,把数据10赋值给数组的第3个元素,第3个元素就是数组下标为2的元素。赋值之后,元素的值由0变成了10。数组名[索引]可以看成是一个变量。
3. array[1] = array[0] + array[2]; 这一行仍然是赋值语句,计算array[0] + array[2]的值,将结果赋值给array[1]。即 20 + 10的值30赋值给array[1],赋值之后,元素的值变为30。数组名[索引]可以看成是一个变量。
所以当执行打印语句的时候,打印的结果分别是:20、30、10
System.out.println(array[0]);// 20
System.out.println(array[1]);// 30
System.out.println(array[2]);// 10
数组和其他局部变量的内存
public static void main(String[] args) {
int num = 0;
int sum = 0;
int[] array = {10,20,30};//new int[]{10,20,30};
num = array[0] * array[2] / array[1];
sum = array[0] + array[1] + array[2];
System.out.println(num);
System.out.println(sum);
}
局部变量存放在栈区,num、sum、array都是局部变量,因此他们存放在栈区。new开辟的内存在堆区。
下面是定义变量num,sum,array时的内存分配情况:
1. int num = 0; 定义了一个局部变量num,num的初始值是0。局部变量num被存放在了内存 的栈区。如上图所示。
2. int sum = 0;定义了一个局部变量sum,sum的初始值是0。局部变量sum被存放在了内存的 栈区。如图所示。
3. int[] array 定义了一个局部变量array,array的值最终会保存堆区数组的首地址。栈区采用先进后出的方式来管理,即先定义的局部变量在栈底,后定义的局部变量再栈顶。
4. {10, 20, 30}是数组静态初始化的简写模式,完整的写法是 new int[]{10, 20, 30}。new关键字在堆区开辟了12个字节的内存,用于存放3个int数据,数组的首地址是15db9742。
5. 数组一共包含3个int元素,元素的初始值分别是10(array[0])、20(array[1])、30(array[2])。
6. 将数组的首地址15db9742赋值给array变量。即array的值是15db9742。
num = array[0] * array[2] / array[1];
sum = array[0] + array[1] + array[2];
System.out.println(num);
System.out.println(sum);
修改num和sum值的内存图:
1. num = array[0] * array[2] / array[1]; 即 10 * 30 / 20,将结果15赋值给变量num。所以在内存中num的值由0变为了15。
2. sum = array[0] + array[1] + array[2]; 即 10 + 20 + 30,将结果60赋值给变量sum。所以内存中sum的值由0变为了60。
3. 所以打印num和sum的值,分别是15和60。
多个数组内存图
public static void main(String[] args) {
int[] arr1 = new int[2];
int[] arr2 = {15, 10, 20};
System.out.println(arr1);//第一个数组堆区内存地址15db9742
System.out.println(arr1[0]);// 0
System.out.println(arr1[1]);// 0
System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
System.out.println(arr2[0]);// 15
System.out.println(arr2[1]);// 10
System.out.println(arr2[2]);// 20
arr1[0] = 50;
arr1[1] = arr1[0] + arr2[0]; //65
arr2[2] = 28;
System.out.println(arr1);//第一个数组堆区内存地址15db9742
System.out.println(arr1[0]);// 50
System.out.println(arr1[1]);// 65
System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
System.out.println(arr2[0]);// 15
System.out.println(arr2[1]);// 10
System.out.println(arr2[2]);// 28
}
上述代码的输出结果:
数组arr1、arr2内存分配情况:
对于int[] arr1 = new int[2];可以分解为4个步骤:
1. 定义局部变量arr1,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr1
2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是8个字节。这段内存空间的首地址是15db9742。之所以开辟8个字节,是因为需要存放2个int数据,每个int是4个字节,所以是8个字节。
3. 系统为数组的2个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[2]
4. 将数组的首地址赋值给变量arr1,因此arr1的值是地址15db9742
对于int[] arr2 = {15, 10, 20};等价于 int[] arr2 = new int[]{15, 10, 20};仍然可以分解为4个步骤:
1. 定义局部变量arr2,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr2
2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是6d06d69c。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。
3. 为3个数组元素分别赋初始值15,10,20。-----步骤2和3对应的代码是: {15, 10, 20}
4. 将数组的首地址赋值给变量arr2,因此arr2的值是地址6d06d69c
System.out.println(arr1);//第一个数组堆区内存地址15db9742
System.out.println(arr1[0]);// 0
System.out.println(arr1[1]);// 0
System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
System.out.println(arr2[0]);// 15
System.out.println(arr2[1]);// 10
System.out.println(arr2[2]);// 20
上述7行打印的结果是:
修改数组arr1、arr2元素值:
arr1[0] = 50;
arr1[1] = arr1[0] + arr2[0]; //65
arr2[2] = 28;
修改数组元素的内存图如下:
1. arr1[0] = 50; 这行代码的作用是给arr1下标为0的元素(即arr1的第1个元素)赋值,将arr1[0]的值修改成50。
2. arr1[1] = arr1[0] + arr2[0]; 这行代码的作用是给arr1下标为1的元素(即arr1的第2个元素)赋值,将arr1[1]的值修改成65(即 50 + 15)。
3. arr2[2] = 28;这行代码的作用是给arr2下标为2的元素(即arr2的第3个元素)赋值,将arr2[2]的值修改成28。
System.out.println(arr1);//第一个数组堆区内存地址15db9742
System.out.println(arr1[0]);// 50
System.out.println(arr1[1]);// 65
System.out.println(arr2);//第二个数组堆区内存地址6d06d69c
System.out.println(arr2[0]);// 15
System.out.println(arr2[1]);// 10
System.out.println(arr2[2]);// 28
上述7行打印的结果是:
多个数组变量指向相同堆区内存
public static void main(String[] args) {
int[] arr1 = {25, 13, 36};
int[] arr2 = arr1;//将arr1的值赋值给arr2,即arr2和arr1保存了相同的堆区地址。
System.out.println(arr1);// arr1保存的内存地址是15db9742
System.out.println(arr2);// arr2保存的内存地址是15db9742
System.out.println(arr1[0]);// 25
System.out.println(arr2[0]);// 25
System.out.println(arr1[1]);// 13
System.out.println(arr2[1]);// 13
arr1[0] = 100;
arr2[1] = 200;
System.out.println(arr1);// arr1保存的内存地址是15db9742
System.out.println(arr2);// arr2保存的内存地址是15db9742
System.out.println(arr1[0]);// 100
System.out.println(arr2[0]);// 100
System.out.println(arr1[1]);// 200
System.out.println(arr2[1]);// 200
}
上述代码输出的结果:
数组arr1、arr2内存分配情况:
int[] arr1 = {25, 13, 36};的完整格式是: int[] arr1 = new int[]{25, 13, 36};这行代码可以分为4个步骤:
1. 定义局部变量arr1,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr1
2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。
3. 为3个数组元素分别赋初始值25,13,36。-----步骤2和3对应的代码是: {25, 13, 36}
4. 将数组的首地址赋值给变量arr1,因此arr1的值是地址15db9742
int[] arr2 = arr1; 这是一行赋值语句。这行代码可以分为2个步骤:
1. 定义局部变量arr2,数据类型是int[],局部变量存放在了内存的栈区。对应代码:int[] arr2
2. 将变量arr1的值赋值给变量arr2。因为arr1里存放的是堆区地址15db9742,因此赋值以后,arr2的值也是15db9742。相当于有2个数组变量指向了同一块内存区域。所以无论通过arr1访问数组元素还是通过arr2访问数组元素都会得到相同的数据。
System.out.println(arr1);// arr1保存的内存地址是15db9742
System.out.println(arr2);// arr2保存的内存地址是15db9742
System.out.println(arr1[0]);// 25
System.out.println(arr2[0]);// 25
System.out.println(arr1[1]);// 13
System.out.println(arr2[1]);// 13
上述6行代码打印的结果如下:
修改数组元素值的内存图如下:
1. arr1[0] = 100; 通过数组arr1修改了堆区内存中的数据。因为arr2和arr1指向的是相同的内存 区域,所以arr2[0]的值也是100。
2. arr2[1] = 200; 通过数组arr2修改了堆区内存中的数据。因为arr1和arr2指向的是相同的内存 区域,所以arr1[1]的值也是200。
System.out.println(arr1);// arr1保存的内存地址是15db9742
System.out.println(arr2);// arr2保存的内存地址是15db9742
System.out.println(arr1[0]);// 100
System.out.println(arr2[0]);// 100
System.out.println(arr1[1]);// 200
System.out.println(arr2[1]);// 200
上述6行代码打印的结果如下:
数组内存的总结
1. 数组变量存放的是堆区的数组的首地址。数组变量本身存放在栈区,它的值是堆区的地址。
2. 数组元素存放在堆区,通过 数组名[索引]的方式可以访问数组元素。
3. 给数组变量赋值,相当于改变了数组变量的指向。
4. 如果多个数组变量指向了同一个数组,可以通过任意一个数组变量修改数组元素的值。
数组操作的注意事项
数组下标越界
数组下标越界:指的是数组下标的值超出了下标的取值范围。
数组下标的取值范围:0 ~ 数组个数 - 1
例如:
int[] arr = new int[3];
System.out.println(arr);
System.out.println(arr[3]);//此处会产生数组越界问题。数组下标的取值范围是[0, 2],但访问了下标为3的元素。
上面代码运行后,报出了一个异常(Exception),异常的意思是数组的索引超出了边界。下标3超出了下标的范围。简单说就是数组的下标越界。
int[] arr = new int[3]; 可以分解为4个步骤:
1. 定义局部变量arr,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr
2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。
3. 系统为数组的3个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[3]
4. 将数组的首地址赋值给变量arr,因此arr的值是地址15db9742
System.out.println(arr[3]); 这行代码的作用是打印数组下标为3的元素的值,通过上面的图,我们会发现,数组只有3个元素,对应的下标分别是0,1,2。现在要访问下标为3的元素,3超出了数组下标的范围,所以程序会出现异常。开发中应避免出现数组越界的问题。
空指针异常
null是一个常量,用于给引用类型变量赋值。
空指针异常:指的是数组(或对象)指向了一个空地址,如果指向了空地址以后,还在继续访问数据,就会出现空指针异常。
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr);// arr的值是15db9742
arr = null;// 将arr设置为null,即空值(内存地址为0的值)
System.out.println(arr);// null
System.out.println(arr[0]); //空指针异常
}
上面代码运行的结果是:
图中报出了一个异常,异常的意思是空指针异常。出现这种问题的原因就是,数组变量保存的地址已经被清空,数组已不再指向以前的堆区,所以访问数据的时候,就会出现异常。
int[] arr = new int[3]; 可以分解为4个步骤:
1. 定义局部变量arr,数据类型是 int[],局部变量被存放在了内存的栈区。对应代码:int[] arr
2. 通过new关键字,在堆区开辟一段连续的内存空间,开辟的空间大小是12个字节。这段内存空间的首地址是15db9742。之所以开辟12个字节,是因为需要存放3个int数据,每个int是4个字节,所以是12个字节。
3. 系统为数组的3个元素设置默认值0。因为是动态初始化,所以系统来设置默认初始值,int类型元素的初始值默认是0。-----步骤2和3对应的代码是: new int[3]
4. 将数组的首地址赋值给变量arr,因此arr的值是地址15db9742
1. arr = null; 执行之后,arr中原有的值15db9742被清空。无法再指向堆区的数组元素。
2. System.out.println(arr[0]); 这行代码中的 arr[0]出现了异常,原因就是arr已经不再指向任何(有效的)内存地址,所以操作数据的时候,会出现空指针异常。
数组的遍历
什么是数组遍历
数组的遍历:指的是获取数组中的每个元素。
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
System.out.println(arr[4]);
}
上述代码的作用就是遍历并打印每个数组元素的值。这段代码虽然能达到遍历的效果,但是代码质量不高,如果数组有100万条数据,输出语句需要写100万行。
通过观察上述代码,你会发现明显的规律:每条打印语句唯一的区别就是数组的下标不同。下标从0开始,每次下标增1,直到数组个数-1。因此可以使用for循环对数组进行遍历。
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};
for(int i = 0; i < 5; i++) {
System.out.println(arr[i]);
}
}
上面的代码就是简化之后的数组遍历代码。仔细观察不难发现,i 的初始值 0,可以对应数组第 1 个元素的下标0,每循环一次,执行一次 i++, 可以让 i 的值增 1,这样能对应数组的每一个下标。直到 i 的值达到数组元素个数-1,即 i < 数组元素个数。
数组元素个数
因为数组元素个数很重要,所以Java提供了获取数组元素个数的的方式。
格式:数组名.length
示例:arr.length
鉴于此,上述代码可以进一步优化。
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
数组遍历的通用格式
因为每个数组的元素个数,都可以通过数组名.length获得,所以任意一个数组的遍历都可以写成如下形式:
public static void main(String[] args) {
int[] 数组名 = {...};
for(int i = 0; i < 数组名.length; i++) {
数组名[i];//对 数组名[i] 进行操作
}
}
数组遍历示例
public static void main(String[] args) {
int[] arr = {111, 222, 333, 444};
//数组arr的遍历
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
int[] arr2 = {35, 12, 16, 24, 76, 88, 31};
//数组arr2的遍历
for(int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
}
数组的常用操作
数组求最值
1. 需求:有一组数据 10,8,23,41,52,66,34,12。编写代码求出数组中的最大值。
2. 代码:
public static void main(String[] args) {
//需求:有一组数据 10,8,23,41,52,66,34,12。
//编写代码求出数组中的最大值。
//分析:
//1. 这组数据使用 int 数组来保存。---数组的定义、数组的静态初始化。
//2. 定义一个变量 max,用于保存数组中最大的元素。
//3. 遍历数组,让 max 依次和数组中的每个元素比较,如果元素大于max,将max值更新为元素的值。
//4. 一趟循环结束后,max中保存的就是数组中的最大值。
int[] array = {10, 8, 23, 41, 52, 66, 34, 12};
int max = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
System.out.println("max = " + max);
}
数组元素求和、平均值
1. 需求:有一个具有5个 int 数据的数组,数组中的每个元素都是[10, 30]之间的随机数。编写代码求出数组中的元素的和以及元素的平均值,打印出所有高于平均值的数,打印出所有低于平均值的数。
2. 代码:
public static void main(String[] args) {
//需求:有一个具有5个 int 数据的数组,数组中的每个元素都是[10, 30]之间的随机数。
//编写代码求出数组中的元素的和以及元素的平均值,打印出所有高于平均值的数,打印出所有低于平均值的数。
//分析:
//1. 定义一个数组,使用动态初始化为数组赋初始值。
//2. 定义一个变量sum保存元素的和,定义一个变量avg保存数组元素的平均值---平均值变量使用double类型。
//3. 通过循环为每个元素赋值,数组元素的值在[10,30]之间。---循环之前先创建Random对象。
//4. 在循环的过程中,计算元素的和。
//5. 循环结束后,计算元素的平均值。
//6. 遍历数组,打印所有大于平均数的数组元素。
//7. 遍历数组,打印所有小于平均数的数组元素。
int[] array = new int[5];
int sum = 0;
double avg = 0.0;
Random random = new Random();
for(int i = 0; i < array.length; i++) {
array[i] = random.nextInt(30 - 10 + 1) + 10;
System.out.print(array[i] + " ");
sum += array[i];
}
System.out.println();
avg = sum * 1.0 / array.length;
System.out.println("sum = " + sum + ", avg = " + avg);
System.out.print("比平均数大的数是:");
for(int i = 0; i < array.length; i++) {
if(array[i] > avg) {
System.out.print(array[i] + " ");
}
}
System.out.println();
System.out.print("比平均数小的数是:");
for(int i = 0; i < array.length; i++) {
if(array[i] < avg) {
System.out.print(array[i] + " ");
}
}
System.out.println();
}
查找数组元素
1. 需求:有一个包含10个元素的数组,每个元素的值在[10,30]之间,查找数组中是否包含18,如果有18,打印出值为18的元素的下标。如果没有18,打印“数组中不包含18”。
2. 代码:
public static void main(String[] args) {
//需求:有一个包含10个元素的数组,每个元素的值在[10,30]之间,
//查找数组中是否包含18,如果有18,打印出值为18的元素的下标。如果没有18,打印“数组中不包含18”。
//分析:
//1. 定义一个int数组,使用动态初始化为数组赋初始值。
//2. 创建Random对象
//3. 通过循环为每个数组元素赋值
//4. 定义一个boolean类型变量isContain,初始值设置为false,用于记录数组是否包含18,如果包含18,变量值设置为true。
//5. 遍历数组中的元素,判断是否包含18,如果包含18,将isContain设置为true,并结束循环。
//6. 如果遍历数组后,isContain仍然为false,表示数组中不包含18.
int[] array = new int[10];
Random random = new Random();
for(int i = 0; i < array.length; i++) {
array[i] = random.nextInt(30 - 10 + 1) + 10;
System.out.print(array[i] + " ");
}
System.out.println();
boolean isContain = false;
for(int i = 0; i < array.length; i++) {
if(array[i] == 18) {
isContain = true;
break;
}
}
if(isContain == false) {
System.out.println("数组中不包含18.");
}else {
System.out.print("数组中包含18。值为18的元素的下标是:");
for(int i = 0; i < array.length; i++) {
if(array[i] == 18) {
System.out.print(i + " ");
}
}
}
}
3. 需求:有一组已经排好顺序的数据:5,13,19,21,37,56,64,75,80,88,92。编写代码查询数组中是否包含数据78,21,13。
4. 代码:(折半查找方式)
折半查找也叫二分查找。它是一种效率较高的查找方法。但是折半查找要求数据必须有序(升序或者降序)。
折半查找的思想:
定义3个变量分别保存第一个元素(low),最后一个元素(high)以及中间元素的下标(mid),mid = (low + high) / 2。
判断中间元素是否是目标数据,如果是目标数据,表示找到数据;
如果中间元素大于目标数据,说明目标数据在第一个元素和中间元素之间。将high改为mid - 1,更新mid的值(mid = (low + high) / 2);
如果中间元素小于目标数据,说明目标数据在中间元素和最后一个元素之间。将low改为mid + 1,更新mid的值(mid = (low + high) / 2);
继续判断中间元素是否是目标数据,如果是目标数据,表示找到数据;
如果中间元素大于目标数据,说明目标数据在第一个元素和中间元素之间。将high改为mid - 1,更新mid的值(mid = (low + high) / 2);
如果中间元素小于目标数据,说明目标数据在中间元素和最后一个元素之间。将low改为mid + 1,更新mid的值(mid = (low + high) / 2);
重复上述步骤,直到 low > high为止。(或者中间找到了数据)
以查找数据21(目标数据)为例,折半查找的过程如下:
目标数据21和中间数据56相比,由于 56 > 21,所以将high改为mid - 1,mid改为(low + high)/ 2
目标数据21和中间数据19相比,由于19 < 21,所以将low改为mid + 1,mid改为(low + high) / 2
目标数据21和中间数据21相比,数据相等,结束查找。
public static void main(String[] args) {
//需求:有一组已经排好顺序的数据:5,13,19,21,37,56,64,75,80,88,92。
//编写代码查询数组中是否包含数据78,21,13。
//方法二:折半查找方式
int[] array = {5, 13, 19, 21, 37, 56, 64, 75, 80, 88, 92};
int num = 21;
boolean isContain = false;
int low = 0;
int high = array.length - 1;
int mid = (low + high) / 2;
while(low <= high) {
if(array[mid] == num) {
isContain = true;
break;
}else if(array[mid] > num) {
high = mid - 1;
mid = (low + high) / 2;
}else {
low = mid + 1;
mid = (low + high) / 2;
}
}
if(isContain == true) {
System.out.println("查到了数据:" + num);
}else {
System.out.println("数组中没有数据:" + num);
}
}
数组的拷贝
数组的拷贝,涉及到2个数组,一个是源数组,一个是目的数组,将源数组的数据拷贝到目的数组中。目的数组的容量(数组长度)要大于等于源数组的容量。所谓的拷贝,就是把源数组下标为0的元素赋值给目的数组下标为0的元素,把源数组下标为1的元素赋值给目的数组下标为1的元素,....,把源数组下标为length-1的元素赋值给目的数组下标为length-1的元素
1. 需求:创建一个包含10个随机数的数组(源数组),随机数的取值范围是[10, 80],将数组中的数据拷贝到一个新的数组中。
2. 代码:
public static void main(String[] args) {
//需求:创建一个包含10个随机数的数组(源数组),随机数的取值范围是[10, 80],
//将数组中的数据拷贝到一个新的数组中。
//分析:
//1. 创建2个数组,一个数组用于保存10个随机数,另外一个数组用于保存拷贝后的数据,--数组的定义,动态初始化
//2. 创建Random对象
//3. 通过循环产生10个随机数,并输出10个数的值
//4. 编写循环实现拷贝
//5. 打印拷贝结果
int[] sourceArray = new int[10];
int[] destinationArray = new int[sourceArray.length];
Random random = new Random();
for(int i = 0; i < sourceArray.length; i++) {
sourceArray[i] = random.nextInt(80 - 10 + 1) + 10;
System.out.print(sourceArray[i] + " ");
}
System.out.println();
//实现拷贝
for(int i = 0; i < sourceArray.length; i++) {
destinationArray[i] = sourceArray[i];
}
//打印拷贝结果
for(int i = 0; i < destinationArray.length; i++) {
System.out.print(destinationArray[i] + " ");
}
System.out.println();
}
常用
1. 数组是一个容器,用于存储数据。数组在创建的时候要确定容量,数组内部的元素类型必须相同。
2. 数组的长度:数组名.length
3. 数组可以动态初始化,也可以静态初始化。
4. 数组通常和循环结合使用。
5. 数组元素的访问:数组名[下标] -----几维数组就要有几个下标。