05-Java 中的数组

教程 阿布都的都 ⋅ 于 2023-01-06 10:29:24 ⋅ 1043 阅读

数组(Array)

1. 数组概述

数组是用于储存多个相同类型数据的集合,数组中的元素被存储在一段连续的内存空间中。

Java中数组的特点:

  • 数组中存储的数据类型必须相同;
  • 数组既可以存储基本数据类型,也可以存储引用数据类型;
  • 数组的长度固定(一旦数组对象初始化完毕,就不可以改变长度了)

2. 数组的定义和初始化

2.1 数组的定义

声明一个数组有两种方式:

第一种:数据类型[] 数组名

// 例如:
int[] iArr; // 定义了一个int[] 名字叫iArr,该数组就用于存储整数
double[] dArr;

第二种:数据类型 数组名[]

// 例如:
int iArr[];
double dArr[];

通常情况下都是使用第一种方式, 比较适合大多数人的习惯。

2.2 数组的初始化

2.2.1 动态初始化

动态初始化的意思是定义数组时指定数组的长度(即数组可以存储的元素个数),由系统给出数组中元素的默认初始化值。

格式:

数据类型[] 数组名 = new 数据类型[数组长度];

例如:

int[] arr = new int[5];

格式详解

  • 等号左边:

    • int:数组的数据类型

    • []:代表这是一个数组

    • arr:代表数组的名称
  • 等号右边:

    • new:为数组开辟内存空间

    • int:数组的数据类型

    • []:代表这是一个数组

    • 5:代表数组的长度

2.2.2 数组元素访问

数组元素用整个数组的名字和它自己在数组中的顺序位置来表示,这个用于区分数组的各个元素的数字编号称为索引(index),也称为下标。索引从0开始。

访问格式:

数组名[索引]

示例:

public class ArrayDemo {
    public static void main(String[] args) {
        int[] arr = new int[3];
        // 输出数组名
        System.out.println(arr); //[I@880ec60
        // 输出数组中的元素
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

2.2.3 Java中的内存分配

程序,无论是代码还是数据,都需要存储在内存中,JVM为Java程序提供并管理所需要的内存空间。一般Java在内存分配时会涉及到以下区域:

区域名称 作用
寄存器 给CPU使用,和我们开发无关。
本地方法栈 JVM在使用操作系统功能的时候使用,和我们开发无关。
方法区 存储可以运行的class文件。 记录类中的所有信息。
堆内存 存储对象或者数组,new来创建的,都存储在堆内存。
方法栈 方法运行时使用的内存,比如main方法运行,进入方法栈中执行。
  • 线程特点: JVM只有一个堆区,在虚拟机启动时创建,被所有线程共享。

  • 存放数据:堆中存放new出来的对象和数组,对象的成员变量同时在堆内存分配空间。

  • 销毁机制:由JVM的垃圾回收器 (GC)自动管理。对象实例本身存放于堆内存,并不会随方法结束而销毁,且可以被其他变量引用,当没有任何变量引用该对象时,对象成为垃圾,等待垃圾回收器在合适的时间点回收。

  • 数据特点:堆内存中的数据都有默认的初始化值

    • 基本数据类型:

    整数(byte short int long):0

    小数(float double):0.0

    字符(char):'\u0000' (\u开头表示是一个unicode码的字符,'\u0000'显示到控制台上是一个空格)

    布尔类型(boolean):false

    • 引用数据类型(数组 字符串 类 接口等等):null
  • 线程特点:每个线程包含一个栈区。

  • 存放数据:栈中只保存局部变量中的基本数据类型和对象的引用,对象都存放在堆区中。

    每个栈中的数据(原始类型 和 对象引用)都是私有的,其他栈不能访问。

  • 数据特点:栈的优势是,存取速度比堆要快。每个方法执行时,该方法会建立自身的内存栈,也就是栈帧,以便于将该方法内定义的变量(局部变量)加入到栈帧中,方法结束时,栈帧销毁,该方法内的局部变量也随之销毁。

  • 销毁机制:栈中没有垃圾回收机制,只有进栈和弹栈,进栈则分配内存,弹栈则释放内存(遵循后进先出的数据结构特点)。用完即销毁。
方法区
  • 存放数据:方法区主要用于存放对象实例的类(Class文件)信息(对象的类型、父类、实现接口和方法本体等)、常量(常量池,内部含有字符串常量池)、静态(静态区,包含静态变量和静态方法)。

  • 线程机制:方法区被所有线程共享。

  • 销毁机制:垃圾收集行为在方法区很少出现,这块区域回收的主要目标是针对常量池的回收和对类型的卸载。

    程序运行时,类信息加载;程序结束时,类信息卸载。

2.2.4 数组的内存图

file

2.2.5 数组静态初始化

数组静态初始化指的是:在创建数组时,直接将元素确定。

  • 完整格式

    数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...};
  • 简化格式

    数据类型[] 数组名 = {元素1,元素2,...};

示例:

public class ArrayDemo {
    public static void main(String[] args) {
        //定义数组
        int[] arr = new int[] {1, 2, 3};
        // int[] arr = {1, 2, 3};
        //输出数组名
        System.out.println(arr);
        //输出数组中的元素
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

2.2.6 使用数组的注意事项

数组索引越界异常

  • 出现原因

    public class ArrayDemo {
      public static void main(String[] args) {
          int[] arr = new int[3];
          System.out.println(arr[3]);
      }
    }

    数组长度为3,索引范围是0~2,但是我们却访问了一个3的索引。

    程序运行后,将会抛出ArrayIndexOutOfBoundsException 数组索引越界异常。

  • 解决方案

    将错误的索引修改为正确的索引范围即可。

空指针异常

  • 出现原因

    public class ArrayDemo {
      public static void main(String[] args) {
          int[] arr = new int[3];
          //把null赋值给数组
          arr = null;
          System.out.println(arr[0]);
      }
    }

    arr = null 这行代码,意味着变量arr将不会再保存数组的内存地址,也就不允许再操作数组了,因此运行的时候会抛出 NullPointerException 空指针异常。

  • 解决方案

    使用数组对象时先判断对象是否为空,或者保证数组对象真实存在。

3. 数组的常见操作

3.1 数组遍历

  • 数组遍历:就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组的最基本操作。

    public class ArrayTest01 {
      public static void main(String[] args) {
          //定义数组
          int[] arr = {11, 22, 33, 44, 55};
    
          //使用通用的遍历格式
          for(int x = 0; x < arr.length; x++) {
              System.out.println(arr[x]);
          }
      }
    }

    3.2 数组最值

  • 最大值获取:从数组的所有元素中找出最大值。

  • 实现思路:

    • 定义变量,保存数组0索引上的元素
    • 遍历数组,获取出数组中的每个元素
    • 将遍历到的元素和保存数组0索引上值的变量进行比较
    • 如果数组元素的值大于了变量的值,变量记录住新的值
    • 数组循环遍历结束,变量保存的就是数组中的最大值
  • 代码实现:
public class ArrayTest02 {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {12, 45, 98, 73, 60};
        //定义一个变量,用于保存最大值
        //取数组中第一个数据作为变量的初始值
        int max = arr[0];
        //与数组中剩余的数据逐个比对,每次比对将最大值保存到变量中
        for(int x=1; x<arr.length; x++) {
            if(arr[x] > max) {
                max = arr[x];
            }
        }
        //循环结束后打印变量的值
        System.out.println("max:" + max);
    }
}

二维数组

动态初始化

格式:

数据类型[][] 数组名 = new 数据类型[m][n];

m表示这个二维数组,可以存放多少个一维数组
n表示每一个一维数组,可以存放多少个元素

示例:

int[][] arr = new int[2][3];

该数组可以存放2个一维数组,每个一维数组中可以存放3个int类型元素

静态初始化

格式:

数据类型[][] 数组名 = new 数据类型[][] {{元素1,元素2},{元素1, 元素2}};

示例:

int[][] arr = new int[][]{{11,22},{33,44}};

简化格式:

数据类型[][] 数组名 = {{元素1,元素2}, {元素1, 元素2}};

示例:

int[][] arr = {{11,22},{33,44}};

数组中的元素访问

格式:

数组名[索引][索引];

示例:

int[][] arr = new int[][]{{11,22},{33,44}};
arr[1][0]; // 表示访问第2个(索引为1)小数组的第1个(索引为0)元素

二维数组遍历

已知一个二维数组 arr = { {11 , 22 , 33} , {33 , 44 , 55} }; 遍历该数组,取出所有元素并打印。

实现思路:

①:遍历二维数组,取出里面每一个一维数组
②:在遍历的过程中,对每一个一维数组继续完成遍历,获取内部存储的每一个元素

public static void main(String[] args) {
    int[][] arr = {{11 , 22 , 33}, {44 , 55 , 66}};
    // 遍历二维数组,得到每个一维数组
    for (int i = 0; i < arr.length; i++) {
        // 继续遍历每个一维数组,得到每个元素
        for (int j = 0; j < arr[i].length; j++) {
            System.out.print(arr[i][j] + "\t");
        }
        // 每次打印完一个小数组,加换行
        System.out.println();
    }
}
版权声明:原创作品,允许转载,转载时务必以超链接的形式表明出处和作者信息。否则将追究法律责任。来自海汼部落-阿布都的都,http://hainiubl.com/topics/75985
回复数量: 0
    暂无评论~~
    • 请注意单词拼写,以及中英文排版,参考此页
    • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
    • 支持表情,可用Emoji的自动补全, 在输入的时候只需要 ":" 就可以自动提示了 :metal: :point_right: 表情列表 :star: :sparkles:
    • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif,教程
    • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
    Ctrl+Enter