22_一维数组

22_一维数组

一维数组的基本概念

  • 当需要在Java程序中记录单个数据内容时,则声明一个变量即可。
  • 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数组即可,一维数组本质上就是在内存空间中申请一段连续的存储单元(一个个连续的小格子),地址连续。变量的本质是在内存空间中申请一个内存单元。
  • 数组是相同数据类型的多个元素的容器元素按线性顺序排列,在Java语言中体现为一种引用数据类型

一维数组的声明方式

  • 数据类型[] 数组名称(变量名) = new 数据类型[数组长度];---------------->数据类型决定的是我们申请的内存空间/存储单元有多大并且是什么数据类型的,new是Java中的关键字代表创建、新建,能放多个数据由数组长度决定。

  • 调用数组的length属性可以获取数组的长度:数组名.length

  • 可以通过下标(元素的编号)的方式访问数组中的每一个元素。需要注意的是:数组的下标从0开始,对于长度为n的数组,下标的范围是0 ~ n-1。在这里插入图片描述

    /*
    	编程实现一维数组的声明和使用
     */
     public class ArrayTest {
    	 
    	 public static void main(String[] args) {
    		 
    		 // 1、声明一个长度为2元素类型为int类型的一维数组
    		 // 数据类型[] 数组名称 = new 数据类型[数组长度];	数组名、类名、变量名都是标识符的一种,严格遵从标识符的命名空间
    		 int[] arr = new int[2]; // 前后两个数组类型必须相等	推荐该方式,更容易与变量的声明区分,提高了代码的可读性
    		 // int arr1[] = new int[2]; // 两种方式从结果上来说是一样的,不推荐使用	C和C++中依旧使用,所以保留了它
    		 // int num = 2;			 // 声明一个初始值为2的变量
    		 
    		 // 2、打印一维数组的长度以及每个元素的数值
    		 System.out.println("数组的长度是:" + arr.length); // 长度为2,下表为0-1
    		 System.out.println("下表为0的元素是:" + arr[0]);  // 0
    		 System.out.println("下表为1的元素是:" + arr[1]);  // 0 默认值是0
    		 // 编译Ok,运行时发生ArrayIndexOutOfBoundsException数组下标越界异常
    		 // System.out.println("下表为2的元素是:" + arr[2]); //  数组下标越界异常
    		 
    		 System.out.println("---------------------------------------------");
    		 // 使用for循环打印数组中的所有元素
    		 for(int i = 0; i < arr.length; i ++) {
    			 System.out.println("下表为" + i + "的元素是:" + arr[i]); // 代码的重复性变低
    		 }
    	 }
     }
    

一维数组的初始化方式

  • 基本类型的数组(数组元素为基本类型)创建后,其元素的初始值:byte、short、char、int、long为0;float、double为0.0;boolean为false。

  • 结论:当我们声明了一个数组,只指定了长度,但没指定初始值时,这些数组中的元素都有默认值。

  • 动态方式:给定长度,但没给定初始值

  • 静态方式:可以在数组声明的同时进行初始化,具体如下:

    • 数据类型[] 数组名称 = {初始值1, 初始值2, …};

      // 声明一个长度为5 元素类型为double类型的一维数组
      		 double[] arr2 = new double[5];	// 动态方式
      		 // 打印数组中每个元素值
      		 for(int i = 0; i < arr2.length; i ++) {
      			 System.out.println("下表为" + i + "的元素是:" + arr2[i]); // 全是 0.0
      		 }
      		 
      		 
      		 // 结论:当我们声明了一个数组,只指定了长度,但没指定初始值时,这些数组中的元素都有默认值
      		 System.out.println("---------------------------------------------");
      		 // 5、声明数组的同时就对数组中的元素进行初始化		静态方式	静态方式的简化写法
      		 char[] arr3 = {'a', 'b', 'c', 'd'};
      		 // 打印数组中的每个元素值
      		 for(int i = 0; i < arr3.length; i ++) {
      			 System.out.println("下表为" + i + "的元素是:" + arr3[i]); // a b c d
      		 }
      		 
      		  System.out.println("---------------------------------------------");
      		  // 6、特殊写法---------> 依然是   静态方式	静态方式的完整写法
      		  boolean[] arr4 = new boolean[]{true, true, false, false};
      		  for(int i = 0; i < arr4.length; i ++) {
      			 System.out.println("下表为" + i + "的元素是:" + arr4[i]); // true  true  false  false
      		 }
      
  • 数组的初始化就两种:要么给长度,它取默认初始值(动态初始化);要么给初始值,它可以算出长度(静态初始化)。

内存结构分析

  • 概念:当声明一个变量时本质上就是在内存空间中申请一块存储单元。声明一维数组的时候 int[] arr 和变量的声明 int num 相比,只是多了一个[]。按照之前的原理,int num 会在内存空间中申请一块存储单元/存储区域,int[] arr 也会在内存空间中申请一块存储单元/存储区域。但是数组声明的时候又有一个 new(新建、创建)。而数组的声明,int[] arr1 是在申请存储单元,new int[2] 也是在申请存储单元,还使用 = 把 int[] arr1 进行初始化,那么,二者之间到底是什么关系呢?
内存结构之栈区
  • 栈用于存放程序运行过程当中所有的局部变量。从内存空间中划分的一块区域,一个运行的Java程序从开始到结束会有多次变量的声明。一个Java程序中所有局部变量的声明,本质上都会在栈中申请内存空间。在方法体中直接声明的变量就是局部变量。
  • int num,int[] arr1 在执行时本质上它们的底层都会在栈中申请一个内存空间

内存结构之堆区

  • JVM会在其内存空间中开辟一个称为"堆"的存储空间,这部分空间用于存储使用new关键字创建的数组和对象。所有通过new出来的都在堆区。

整个白色的面板我们就把它当作是内存条的区域,栈区就好比在内存区域中申请了一块地盘,两条竖线代表的是我们在整个内存区域中划分出来的一块区域,这片区域我们就叫栈区。区域还很大,我们又在另外一块地盘又申请了一块区域,叫做堆区。只是人为命名了两块区域。内存0x10是new int[2] 的内存地址,= 把这个地址信息放到栈中arr1,这样我们 arr1 就可以通过内存地址拿到堆中对应地址的数据了。这里就是通过 = 把堆和栈相关联了。

int num = 2; 
/**
  num是一个局部变量,局部变量都在栈区中申请内存空间。
  运行这行代码的时候, 就是在栈区中申请了一块int类型大小的区域,里面放的数据是2。
  理解:在栈区中申请了一块地盘,这块地盘给了一个名字叫num的变量,里面的值放的是2。-----------如下图
 */

int[] arr1 = new int[2];
/**
	对于数组的声明,先执行左边,再执行右边,然后执行 = 。这个 = 叫做赋值运算符。当我们执行左边的时候,它实际上是相当于,声明了一个局部变量,而只要声明了一个局部变量,就意味着要在栈区中申请一块地盘给arr1。-----如下图
	然后后面new int[2] 我们说了所有new 的东西都在堆区,申请了两个int。相当于在堆区中申请了两个int那么大的内存空间。这块内存空间的长度是2,那么下标应该是0和1。我们声明数组的时候由于没给初始值,它会有默认值,此处的默认值是两个0。
	接下来,等号左边的内存图和等号右边的内存图也画完了,接下来就剩一个等号了。= 叫赋值,赋值运算符的作用是:等号右边的值赋给等号左边的变量名。而右边又是申请了一块内存区域。内存区域肯定会有一个地址,在堆区中申请了一块地盘,那么,这块地盘肯定得有一个标识符。这个标识符叫内存地址,假设是0x10,代表的是这块内存空间的地址。
	= 号是将右边的值赋给左边的变量名,右边只有一块内存区域,唯一能代表这块内存区域的就是内存地址,于是将这块区域的地址拷贝了一份放到了栈区中。实际上,arr1这个变量在栈区中放的是一个堆区的地址信息,通过堆区的这个地址信息,可以找到堆区中的那块内存空间。有了堆区的这块内存空间,可以通过变量名可以取得里面的数据,而里面的数据代表的是堆区中的内存地址,通过内存地址可以找到这块内存区域,然后再通过下标可以把里面的数据取出来并且进行打印或者使用。这样一来,栈区和堆区就进行的关联了。这才是声明数组的本质。等号左边做的事情和等号右边做的事情实际上是不一样的。
	一旦建立了关联,以后我们再想找地址为 0x10 的这块堆区的时候,我们只需要找栈区中的arr1这个变量名即可,通过arr1可以一路找过来,因为它们已经建立了关系。
 */

基本数据类型和引用数据类型最根本的区别:基本数据类型的变量内存空间中直接放的是具体的数据内容,而引用数据类型的变量内存空间中存放的是一个内存地址,是一个指向堆区的地址。也就是基本数据类型的变量,给一个小格子就行了,而引用数据类型的变量底层很复杂,比基本数据类型赋值多了。数组是一个数据类型,数组名仅仅记录的是一个代表地址的东西。

// 7、直接通过数组名来打印数组中的所有元素
		 System.out.println("arr = " + arr); // arr = [I@411f53a0  这就是地址信息	
		 // 所以我们通过数组名无法打印数组信息,要想打印数组中的所有元素,只能通过数组名加下标的形式打印	
		 // 数组名可以找到内存空间,再通过下标可以取到里面的数据内容,然后再打印出来,这才是变量和一维数组的底层内存结构

在这里插入图片描述

案例:-------------此处的图片只画了堆区,栈区没有画

  • 声明一个长度为5元素类型为int类型的一维数组,打印数组中所有元素值;

    在这里插入图片描述

  • 使用11、22、33、44分别对数组中前4个元素赋值后再次打印;

    在这里插入图片描述

  • 将元素55插入到下标为0的位置,原有元素向后移动,再打印所有元素值;

    在这里插入图片描述

  • 将元素55从数组中删除,删除方式为后续元素向前移动,最后位置置为0并打印;

    在这里插入图片描述

  • 查找数组中是否存在元素22,若存在则修改为220后再次打印所有元素;

    在这里插入图片描述

    /*
    	编程实现一维数组的增删改查操作
     */
     public class ArrayOpTest {
    	 
    	 public static void main(String[] args) {
    		 
    		 // 1、声明一个长度为5元素类型为int类型的一维数组,打印数组中所有元素值;
    		 int[] arr = new int[5];
    		 // 打印数组中所有元素值
    		 System.out.print("数组中的元素有:");
    		 for(int i = 0; i < arr.length; i ++) {
    			 System.out.print("arr[" + i +"] = " + arr[i] + "\t");
    		 }
    		 System.out.println();
    		 
    		 System.out.println("------------------------------------------------------------------------");
    		 // 2、使用11、22、33、44依次对数组中前4个元素赋值后再次打印;
    		/* arr[0] = 11;
    		 arr[1] = 22;
    		 arr[2] = 33;
    		 arr[3] = 44;*/
    		 for(int i = 0; i < arr.length - 1; i ++) {
    			 arr[i] = (i + 1) * 11;
    		 }
    		  // 打印数组中所有元素值
    		 System.out.print("数组中的元素有:");
    		 for(int i = 0; i < arr.length; i ++) {
    			 System.out.print("arr[" + i +"] = " + arr[i] + "\t"); // 11  22  33 44 0
    		 }
    		 System.out.println();
    		 
    		 System.out.println("------------------------------------------------------------------------");
    		 // 3、将元素55插入到下标为0的位置,原有元素向后移动,再打印所有元素值;
    		 /*arr[4] = arr[3];
    		 arr[3] = arr[2];
    		 arr[2] = arr[1];
    		 arr[1] = arr[0];
    		 arr[0] = 55;*/
    		 for(int i = arr.length - 1; i > 0; i --) {
    			 arr[i] = arr[i-1];
    		 }
    		 arr[0] = 55;
    		 // 打印数组中所有元素值
    		 System.out.print("数组中的元素有:");
    		 for(int i = 0; i < arr.length; i ++) {
    			 System.out.print("arr[" + i +"] = " + arr[i] + "\t"); // 55  11  22  33 44 
    		 }
    		 System.out.println();
    		 
    		 System.out.println("------------------------------------------------------------------------");
    		 // 4、将元素55从数组中删除,删除方式为后续元素向前移动,最后位置置为0并打印;
    		 /*arr[0] = arr[1];
    		 arr[1] = arr[2];
    		 arr[2] = arr[3];
    		 arr[3] = arr[4];
    		 arr[4] = 0;*/
    		 for(int i = 0; i < arr.length - 1; i ++) {
    			 arr[i] = arr[i+1];
    		 }
    		 arr[arr.length-1] = 0;
    		 // 打印数组中所有元素值
    		 System.out.print("数组中的元素有:");
    		 for(int i = 0; i < arr.length; i ++) {
    			 System.out.print("arr[" + i +"] = " + arr[i] + "\t"); // 11  22  33 44 0
    		 }
    		 System.out.println();
    		 
    		 System.out.println("------------------------------------------------------------------------");
    		 // 5、查找数组中是否存在元素22,若存在则修改为220后再次打印所有元素;
    		 for(int i = 0; i < arr.length; i ++) {
    			 if(22 == arr[i]) {
    				 arr[i] = 220;
    				 break;
    			 }
    		 }
    		 // 打印数组中所有元素值
    		 System.out.print("数组中的元素有:");
    		 for(int i = 0; i < arr.length; i ++) {
    			 System.out.print("arr[" + i +"] = " + arr[i] + "\t"); // 11  220  33 44  0
    		 }
    		 System.out.println();
    	 }
     }
    

一维数组的优缺点

优点:

  • 可以直接通过下标(或索引)的方式访问指定位置的元素,速度很快。---------因为数组是一段连续的空间,都有下标,可以通过下标快速定位

缺点:

  • 数组要求所有元素的类型相同
  • 数组要求内存空间连续,并且长度一旦确定就不能修改
  • 增加和删除元素时可能移动大量元素,效率低。

案例:一维数组之间元素拷贝实现

  • 声明一个初始值为 11 22 33 44 55 的一维数组并打印所有元素

  • 声明一个长度为3元素类型为int类型的一维数组并打印所有元素

  • 实现将第一个数组中间3个元素赋值到第二个数组中

  • 再次打印第二个数组中的所有元素

    /*
    	编程实现数组之间元素的拷贝
     */
     public class ArrayCopyTest {
    	 
    	 public static void main(String[] args) {
    		 
    		 // 1、声明一个初始值为 11	22	33	44	55 的一维数组并打印所有元素
    		 //  int[] arr = new int[]{11, 22, 33, 44, 55};  静态声明
    		 int[] arr = {11, 22, 33, 44, 55};
    		 // 打印数组中的所有元素
    		 System.out.print("第一个数组中的元素有:");
    		 for(int i = 0; i < arr.length; i ++) {
    			 
    			 System.out.print("arr[" + i + "] = " + arr[i] + "\t"); //  11 22 33 44 55
    		 }
    		 System.out.println();
    		 
    		 
    		 System.out.println("---------------------------------------------------------");
    		 // 2、声明一个长度为3元素类型为int类型的一维数组并打印所有元素
    		 int[] brr = new int[3];
    		 // 打印数组中的所有元素
    		 System.out.print("第二个数组中的元素有:");
    		 for(int i = 0; i < brr.length; i ++) {
    			 
    			 System.out.print("brr[" + i + "] = " + brr[i] + "\t"); // 0 0 0
    		 }
    		 System.out.println();
    		 
    		 
    		 System.out.println("---------------------------------------------------------");
    		 // 3、实现将第一个数组中间3个元素赋值到第二个数组中
    		 brr[0] = arr[1];
    		 brr[1] = arr[2];
    		 brr[2] = arr[3];
    		 
    		 
    		 // 4、再次打印第二个数组中的所有元素
    		 System.out.print("第二个数组中的元素有:");
    		 for(int i = 0; i < brr.length; i ++) {
    			 
    			 System.out.print("brr[" + i + "] = " + brr[i] + "\t"); // 0 0 0
    		 }
    		 System.out.println();
    	 }
     }
    

一维数组之间元素的拷贝优化

  • jdk API手册----------------->Overview------------------>java.base模块-------------------->java.lang包--------------------->System类------------------>arraycopy方法----------->arraycopy(Object src, int srcPos, Object dest, int destPos, int length)------------------------>第一个参数:数据来源数组,第二个参数:数据来源起始位置,第三个参数:数据去向数组,第四个参数:数据所到目标地址的起始下标,第五个参数:元素的长度/个数

  • 原理:图只画了堆区的在这里插入图片描述

     		System.out.println("---------------------------------------------------------");
    		 // 3、实现将第一个数组中间3个元素赋值到第二个数组中
    		 /*brr[0] = arr[1];
    		 brr[1] = arr[2];
    		 brr[2] = arr[3];*/
    		 /* for(int i = 0; i < brr.length; i ++) {
    			 brr[i] = arr[i + 1];
    		 }*/
    		 // 可以直接使用Java官方提供的拷贝功能
    		 // 表示将数组arr中下标从1开始的3个元素拷贝到数组brr中下标从0开始的位置
    		 System.arraycopy(arr, 1, brr, 0, 3);
    

一维数组之间拷贝的笔试考点

在这里插入图片描述

// 5、笔试考点
		 // 表示将变量 arr 的数值赋值给变量 brr, 覆盖变量 brr 中原来的数值
		 // 数组名arr的内存空间中存放的是数据在堆区中的内存地址信息,复制后让 brr 变量中也存放了arr所指向堆区的内存地址
		 // 也就是让 brr 和 arr指向了同一块堆区空间,本质上就是改变指向而已
		 // 严格来说 brr 中的0x30被0x20覆盖了,此处只是为了不破坏数据的原始性,让我们看起来更直观
		 brr = arr; 
		 System.out.print("第二个数组中的元素有:");
		 for(int i = 0; i < brr.length; i ++) {
			 
			 System.out.print("brr[" + i + "] = " + brr[i] + "\t"); // 0 0 0
		 }
		 System.out.println();

		// 改变了指向之后,原有的0x30内存空间就没有人指向了,没有人指向了的话,0x30内存空间就丢了。此时Java虚拟机有另外一个机制:垃圾回收机制,当它扫描到这块内存空间没有任何人使用的时候,它就将可以这块内存空间释放掉

案例:一维数组统计数字次数

  • 编程统计用户输入一个正整数中每个数字出现次数的统计并打印

  • 比如:123123 => 1 出现2次,2 出现2次,3 出现2次

  • 原理分析:任意一个正整数拆分出来的数字:0 ~ 9,拆分数字:不断用数字对10取余再对10取商。10进制中的任意数字只可能是0~9之间的。统计方法:拆分出来的数字就是数组的下标,数组出现的次数就是数组下标对应的元素值。

    在这里插入图片描述

  • 编码实现:

    /*
    	编程使用数组实现正整数中每个数字出现次数的统计
     */
     import java.util.Scanner;
     
     public class ArrayCountTest {
    	 
    	 public static void main(String[] args) {
    		 
    		 // 1、提示用户输入一个正整数并使用变量记录
    		 // 当在程序中要记录多条数据的时候使用数组
    		 System.out.println("请输入一个正整数:");;
    		 Scanner sc = new Scanner(System.in);
    		 int num = sc.nextInt();
    		 
    		 // 2、准备一个长度为10元素类型为int类型的一维数组, 默认值为 0 
    		 int[] arr = new int[10];
    		 
    		 // 3、拆分正整数中的每个数字并统计到一个一维数组中
    		 int temp = num; // 保证原始数据完整性
    		 while(temp > 0) { // 明确循环条件但不明确循环次数
    			 arr[temp%10] ++;
    			 temp /= 10;
    		 }
    		 
    		 // 4、打印最终的统计结果
    		 for(int i = 0; i < arr.length; i ++) {
    			 if(arr[i] > 0) { // 出现了才打印,不出现就不打印
    				 
    				 System.out.println("数字" + i + "出现了" + arr[i] + "次!");
    			 }
    		 }
    	 }
     }
    

    在这里插入图片描述

案例:数组实现学生考试成绩的录入和打印

  • 提示用户输入学生的人数(变量)以及每个学生的考试成绩(数组)并打印出来。-----------------一个数组的长度可以是一个变量

  • 计算该班级的总分和平均分,并打印出来。

    /*
    	编程使用数组来记录学生的考试成绩	声明数组的长度还可以使用变量
     */
     import java.util.Scanner;
     
     public class ArrayScoreTest {
    	 
    	 public static void main(String[] args) {
    		 
    		 // 1、提示用户输入学生的人数并使用变量记录
    		 System.out.println("请输入学生的人数:");
    		 Scanner sc = new Scanner(System.in);
    		 int num = sc.nextInt();
    		 
    		 // 2、根据学生人数来声明对应长度的数组负责记录学生的考试成绩
    		 // 变长数组:主要指变量可以作为数组的长度,但绝不是数组的长度可以发生改变
    		 int[] scores = new int[num];
    		 
    		 // 3、提示用户输入每个学生的考试成绩并记录到一维数组中
    		 int scoreSum = 0;
    		 for(int i = 0; i < num; i ++) {
    			 System.out.println("请输入第" + (i + 1) + "个学生的考试成绩:");
    			 scores[i] = sc.nextInt();
    			 scoreSum += scores[i];
    		 }
    		 
    		 // 4、打印所有学生的考试成绩
    		 System.out.println("本班学生的考试成绩分别是:");
    		 for(int i = 0; i < scores.length; i ++) {
    			 System.out.print(scores[i] + " ");
    		 }
    		 System.out.println("本班学生考试成绩的总分是:" + scoreSum + ", 平均分是:" + (scoreSum / num));
    	 }
     }
    

案例:数组实现学生成绩总分和平均分的计算

 // 5、计算本班学生的总分以及平均分并使用变量记录
		 int sum = 0;
		 for(int i = 0; i < scores.length; i ++) {
			 sum += scores[i];
		 }
		 double avg = sum/num*1.0;
		 
		 // 6、打印最终的计算结果
		 System.out.println("本班级学生的总分是:" + sum + ", 平均分是:" + avg);
是:");
  		 for(int i = 0; i < scores.length; i ++) {
  			 System.out.print(scores[i] + " ");
  		 }
  		 System.out.println("本班学生考试成绩的总分是:" + scoreSum + ", 平均分是:" + (scoreSum / num));
  	 }
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一维数组和二维数组是两种不同维度的数据结构,在计算机编程中用来存储和组织数据。 1. 一维数组(One-dimensional Array): 一维数组是一组相同类型的元素按照线性顺序排列,每个元素都有唯一的索引。比如在C/C++中,你可以创建一个整型的一维数组`int arr`,这表示一个包含5个整数的数组,索引从0开始(arr, arr, ..., arr)。 2. 二维数组(Two-dimensional Array): 二维数组是由多个一维数组构成的,每个一维数组代表一个行,而所有行组成一个矩阵。在数学或编程中,它们通常用方括号表示,如`int arr`,表示一个3行4列的数组,可以通过索引`arr[i][j]`访问其中的元素,其中i表示行索引,j表示列索引(0-based indexing, `arr`为左上角元素)。 区别: - **维度**:一维数组只有单层,而二维数组有两层,分别对应行和列。 - **存储**:一维数组是连续的内存空间,而二维数组每个元素在内存中的位置可能不连续。 - **用途**:一维数组适合表示线性数据序列,如时间序列;二维数组常用于表格数据或矩阵运算。 - **索引**:一维数组使用单一索引,二维数组则需两个索引来定位元素。 相关问题: 1. 除了整型,还有哪些数据类型可以用于创建数组? 2. 如何在Python中创建和初始化二维数组? 3. 一维数组和二维数组在内存分配上有什么不同?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值