java数组

2023-12-14 21:45:29

1. 概述

  • 定义:数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。

  • 常见概念:数组名,下标(或索引),元素,数组的长度

  • 特点:

    • 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。

    • 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址。

    • 数组的长度一旦确定,就不能修改。

    • 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。

    • 数组的分类:

      • 按照维度:一维数组、二维数组、三维数组、...

      • 按照元素的数据类型分:基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)

  • 语法结构:

    元素的数据类型[] 数组名称 = new 元素的数据类型[数组容器的大小];
    // 1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行
     ? int[] arr1 = new int[]{1, 2, 3, 4, 5};
    // 1.2动态初始化:数组的初始化和数组元素的赋值操作分开进行
     ? double[] arr2 = new double[5];
  • 语法解释:

    • 元素:数组中的数据、数组中的变量

    • 元素的数据类型:数组中的数据的数据类型

    • []:表示是一个一维数组

    • 数组名称:数组本身也是一个变量,用于存储数组的地址的变量

    • =:赋值符号,将数组的地址,赋值给数组的名称

    • new:用于在堆内存中开辟空间

    • 元素的数据类型:和前面的元素的数据类型保持一致

    • 数组容器的大小:可以存储数据的个数

  • 打印数组的结果:[D@5cad8086

    • [:表示这是一个一维数组

    • D:表示数组中存储的是 double 类型的数据

    • @:普通的分隔符,没有具体的含义

    • 5cad8086:数组有一个内存地址

2. 数组的初始化

  • 为数组分配空间,并且赋值。

  • 分类:

    • 静态初始化:在程序书写的时候,就知道了数组中的元素是什么值

    • 动态初始化:程序运行过程中,才能知道究竟给元素赋什么值

2.1 静态初始化

  • 语法结构:

    元素的数据类型[] 数组名称 = new 元素的数据类型[] {元素值的罗列};
    ?
    或
     ?
    元素的数据类型[] 数组名称 = {元素值的罗列};
  • 语法示例:

    double[] douArr = new double[] {9.9d,8.7,7,0};
    ?
    或
    ?
    double[] douArr = {9.9d,8.7,7,0};
  • 注意事项:

    • 在第二个方括号中,不要写数组元素的个数。

    • 元素值的罗列,元素和元素之间,使用逗号分隔,写了几个元素,就分配多大空间。

    • 罗列出来的元素值,数据类型必须和声明的数组元素的数据类型一致。

    • 数组名称的声明,数组名称的赋值,不能分成两行写。

2.2 动态初始化

  • 语法结构:

    元素的数据类型[] 数组名称 = new 元素的数据类型[数组元素的个数];
  • 语法示例:

    // 声明一个数组并初始化为3个长度
    double[] douArr = new double[3];
    ?
    // 给元素赋值,方式:数组名称[元素的索引] = 元素值;
    douArr[0] = 3.5;
    douArr[1] = 4d;
    douArr[2] = 7;
  • 元素索引:下角标;从0开始,数组长度 -1结束。

  • 注意事项:

    • 所有的元素,都需要逐个赋值。

    • 如果数组中的元素,没有赋值,元素也有一个默认的初始化值,为各数据类型的默认值。

       * ? ?> 数组元素是整型:0
       *      > 数组元素是浮点型:0.0
       *      > 数组元素是char型:'\u0000',而非""
       *      > 数组元素是boolean型:false
       *      > 数组元素是引用数据类型:null
       ? ? ? ?int[] arr = new int[4];
       ? ? ? ?System.out.println(arr[0]);
       ? ? ? ?boolean[] arr1 = new boolean[5];
       ? ? ? ?System.out.println(arr1[0]);
                      String[] arr2 = new String[5];
       ? ? ? ?System.out.println(arr2[0]);
  • 错误写法:

    ? ?int[] arr1 = new int[];
            int[5] arr2 = new int[5];
            int[] arr3 = new int[3]{1,2,3};

3. 数组的内存理解

  • JVM 是执行 Java 的容器,空间很大,按照不同的功能、不同的特点划分了三个区域:堆内存(heap)栈内存(stack)方法区(method)

  • 堆内存【常用】:用于存储数组、对象等数据量较大的数据。一般都是引用数据类型。

  • 栈内存【常用】:用于执行方法,每个方法单独的分配一段空间,称为栈帧,把给方法分配内存空间,形象的称为“进栈”。特点:先进后出

  • 方法区【常用】:用于存储类的字节码对象,存储常量、存储静态变量。

image-20230131224010010

演示下静态初始化数组的存放方式
 int[] arr = new int[]{1, 2, 3}; 

分析下方代码的运行结果:

   public static void main(String[] args) {
 ? ? 
 ? ? ? ?String[] arr1 = new String[4];
 ? ? ? ?arr1[1] = "刘德华";
 ? ? ? ?arr1[2] = "张学友";
 ? ? ? ?arr1 = new String[3];
 ? ? ? ?System.out.println(arr1[1]);
 ?  }

image-20230131224744598

4. 数组异常

4.1 数组下角标越界异常

  • 异常代码:
    
    public static void main(String[] args) {
     ? ?int[] intArr = new int[2];
     ? ?System.out.println(intArr[2]);
    }
  • 异常显示:

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
  • 异常原因:访问了数组中不存在的索引,超过元素索引范围,都会出现异常情况。

4.2 空指针异常

  • 异常代码:

    public static void main(String[] args) {
     ? ?int[] intArr = {3, 5, 9};
     ? ?intArr = null;
     ? ?System.out.println(intArr[0]);
    }
  • 异常显示:

    Exception in thread "main" java.lang.NullPointerException
  • 异常原因:当引用不再指向任何的堆内存中的数据时,仍然要通过这个引用访问堆内存中的数据,只能抛出异常。

  • 避免方式:

    public static void main(String[] args) {
     ? ?int[] intArr = {3, 5, 9};
     ? ?intArr = null;
     ? ?if (intArr != null) {
     ? ? ? ?System.out.println(intArr[0]);
     ?  }
    }

5. 数组的操作

5.1 数组赋值

  • 语法结构:

    数组名称[元素的索引] = 元素值;
  • 语法示例:

    double[] douArr = {3.5d, 4};
    douArr[0] = 7;

5.2 数组遍历

  • 遍历:每个元素都要访问一遍。

  • 方式:循环数组的索引,通过索引访问数组的值。

  • 示例:

    public static void main(String[] args) {
     ? ?double[] douArr = {3.5d, 4, 7, 4.6f};
     ? ?for (int i = 0; i < douArr.length; i++) {
     ? ? ? ?System.out.println(douArr[i]);
     ?  }
    }
  • 增强for循环:

    public static void main(String[] args) {
     ? ?double[] douArr = {3.5d, 4, 7, 4.6f};
     ? ?for (double dob : douArr) {
     ? ? ? ?System.out.println(dob);
     ?  }
    }

6. 二维数组

6.1 概述

  • 二维数组:数组的嵌套,数组里的每一个元素都是一个数组。

  • 对于二维数组的理解,我们可以看成是一维数组 array1又作为另一个一维数组array2的元素而存在。

  • 语法结构:

    元素的数据类型[][] 数组名称 = new 元素的数据类型[外层数组容器的大小][每个外层数组内包含的数组容器大小];
  • 语法示例:

    int[][] arr = new int[3][2];
  • 示例解释:

    • 定义了名称为arr的二维数组

    • 二维数组中有3个一维数组

    • 每一个一维数组中有2个元素

    • 一维数组的名称分别为arr[0], arr[1], arr[2]

    • 给第一个一维数组1脚标位赋值为78写法是:arr[0] [1] = 78;

       public static void main(String[] args) {
       ? ? ? ?int[][] arr = new int[3][2];
       ? ? ? ?System.out.println(arr[0][1]);
       ? ? ? ?arr[0][1] = 78;
       ? ? ? ?System.out.println(arr[0][1]);
       ?  }
  • 语法变型:

    • 变型1:

      • 语法示例

        int[][] arr = new int[3][];
      • 分析下方代码:

         public static void main(String[] args) {
         ? ? ? ?int[][] arr = new int[3][];
         ? ? ? ?System.out.println(arr[0]);
         ? ? ? ?arr[0] = new int[1];
         ? ? ? ?arr[1] = new int[2];
         ? ? ? ?arr[2] = new int[3];
         ? ? ? ?System.out.println(arr[0][0]);
         ? // ? int[][]arr = new int[][3]; //非法
         ?  }
    • 示例解释:

      • 二维数组中有3个一维数组。

    • 每个一维数组都是默认初始化值null (区别于实例1)

      • 可以对这个三个一维数组分别进行初始化

      • arr[0] = new int[1]; arr[1] = new int[2]; arr[2] = new int[3];

    • 变型2:

      • 语法示例:(静态初始化)

        int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};
      • 示例解释:

        • 定义一个名称为arr的二维数组,二维数组中有三个一维数组

        • 每一个一维数组中具体元素也都已初始化

        • 第一个一维数组 arr[0] = {3,8,2};

        • 第二个一维数组 arr[1] = {2,7};

        • 第三个一维数组 arr[2] = {9,0,1,6};

        • 第三个一维数组的长度表示方式:arr[2].length;

           ?public static void main(String[] args) {
           ? ? ? ?int[][] arr = new int[][]{{3, 8, 2}, {2, 7}, {9, 0, 1, 6}};
           ? ? ? ?System.out.println(arr[0]);
           ? ? ? ?System.out.println(arr[2].length);
           ?  }

6.2 二维数组遍历

  • 方式:嵌套循环,先循环外层数组,再循环每个外层数组内的一维数组。

  • 示例:

    public static void main(String[] args) {
     ? ?// 声明一个int类型的二维数组,并赋值
     ? ?int[][] arr = {{2, 4}, {3, 6, 4}, {0, 2, 4, 10}};
     ? ?// 先循环外层的数组,变量i为数组的下角标
     ? ?for (int i = 0; i < arr.length; i++) {
     ? ? ? ?// 变量ins为外层数组的值,其本身就是一个int类型的一维数组
     ? ? ? ?int[] ins = arr[i];
     ? ? ? ?// 循环外层数组内的一维数组,变量j为一维数组的小角标
     ? ? ? ?for (int j = 0; j < ins.length; j++) {
     ? ? ? ? ? ?// 变量in为外层数组内遍历的一维数组内的值
     ? ? ? ? ? ?int in = ins[j];
     ? ? ? ? ? ?// 打印该值,但不换行
     ? ? ? ? ? ?System.out.print(in + "\t");
     ? ? ?  }
     ? ? ? ?// 每循环一个外层数组后,进行换行的操作
     ? ? ? ?System.out.println();
     ?  }
    }

7. 冒泡排序

  • 方式:循环遍历数组,临近的两个元素比较大小;升序(将较小的元素放置在左侧);降序(将较大的元素放置在右侧)。

  • 升序代码示例:

    public static void main(String[] args) {
     ? ?// 初始化一个数据顺序不规则的数组
     ? ?int[] ins = {10, 1, 37, 25, 8, 5, 46, 93, 2};
     ? ?// 依次循环数组元素,循环多少轮
     ? ?for (int i = 0; i < ins.length - 1; i++) {
     ? ? ? ?// 循环需要比较的数据,每轮比较的次数
     ? ? ? ?for (int j = 0; j < ins.length - 1 - i; j++) {
     ? ? ? ? ? ?// 交换数据
     ? ? ? ? ? ?if (ins[j] > ins[j + 1]) {
     ? ? ? ? ? ? ? ?int temp = ins[j];
     ? ? ? ? ? ? ? ?ins[j] = ins[j + 1];
     ? ? ? ? ? ? ? ?ins[j + 1] = temp;
     ? ? ? ? ?  }
     ? ? ?  }
     ?  }
     ? ?for (int in : ins) {
     ? ?    System.out.println(in);
     ?  }
    }
  • 降序代码示例:

    public static void main(String[] args) {
     ? ?// 初始化一个数据顺序不规则的数组
     ? ?int[] ins = {10, 1, 37, 25, 8, 5, 46, 93, 2};
     ? ?// 依次循环数组元素,循环多少轮
     ? ?for (int i = 0; i < ins.length; i++) {
     ? ? ? ?// 循环需要比较的数据,每轮比较的次数
     ? ? ? ?for (int j = 0; j < ins.length - 1 - i; j++) {
     ? ? ? ? ? ?// 交换数据
     ? ? ? ? ? ?if (ins[j] < ins[j + 1]) {
     ? ? ? ? ? ? ? ?int temp = ins[j];
     ? ? ? ? ? ? ? ?ins[j] = ins[j + 1];
     ? ? ? ? ? ? ? ?ins[j + 1] = temp;
     ? ? ? ? ?  }
     ? ? ?  }
     ?  }
     ? ?for (int in : ins) {
     ? ?    System.out.println(in);
     ?  }
    }
  • 总结:

    • N个元素需要排序N-1轮

    • 第i轮需要比较N-i次

    • N个元素排序,需要比较(n-1)/2次

    • 效率不高,实现最简单

    数组算法扩展:数组查找

    1.线性查找
    public class ArrayDemo {
     ? ?public static void main(String[] args) {
     ? ? ? ?String[] arr = new String[]{"JJ", "DD", "MM", "BB", "GG", "AA"};
     ? ? ? ?String dest = "BB";
     ? ? ? ?dest = "CC";
     ? ? ? ?boolean isFlag = true;
     ? ? ? ?for (int i = 0; i < arr.length; i++) {
     ? ? ? ? ? ?if (dest.equals(arr[i])) {
     ? ? ? ? ? ? ? ?System.out.println("找到了指定的元素,位置为:" + i);
     ? ? ? ? ? ? ? ?isFlag = false;
     ? ? ? ? ? ? ? ?break;
     ? ? ? ? ?  }
     ? ? ?  }
     ? ? ? ?if (isFlag) {
     ? ? ? ? ? ?System.out.println("很遗憾,没有找到的啦!");
     ? ? ?  }
     ?  }
    }
    2.二分查找
    public class ArrayDemo {
     ? ?public static void main(String[] args) {
     ? ? ? ?int[] arr2 = new int[]{-98, -34, 2, 34, 54, 66, 79, 105, 210, 333};
     ? ? ? ?int dest1 = -34;
     ? ? ? ?dest1 = 79;
     ? ? ? ?int head = 0;//初始的首索引
     ? ? ? ?int end = arr2.length - 1;//初始的末索引
     ? ? ? ?boolean isFlag1 = true;
     ? ? ? ?while (head <= end) {
     ? ? ? ? ? ?int middle = (head + end) / 2;
     ? ? ? ? ? ?if (dest1 == arr2[middle]) {
     ? ? ? ? ? ? ? ?System.out.println("找到了指定的元素,位置为:" + middle);
     ? ? ? ? ? ? ? ?isFlag1 = false;
     ? ? ? ? ? ? ? ?break;
     ? ? ? ? ?  } else if (arr2[middle] > dest1) {
     ? ? ? ? ? ? ? ?end = middle - 1;
     ? ? ? ? ?  } else {//arr2[middle] < dest1
     ? ? ? ? ? ? ? ?head = middle + 1;
     ? ? ? ? ?  }
     ? ? ?  }
     ? ? ? ?if (isFlag1) {
     ? ? ? ? ? ?System.out.println("很遗憾,没有找到的啦!");
     ? ? ?  }
     ?  }
    }

8. Arrays类

  • Arrays工具类:针对数组进行操作的工具类,比如说排序和查找。

  • 包名:java.util.Arrays;

// 方法参数提示 cmd + p
import java.util.Arrays;
?
public class Algorithm {
 ? ?public static void main(String[] args) {
 ? ? ? ?//1.boolean equals(int[] a,int[] b):判断两个数组是否相等。
 ? ? ? ?int[] arr1 = new int[]{1, 2, 3, 4};
 ? ? ? ?int[] arr2 = new int[]{1, 3, 2, 4};
 ? ? ? ?boolean isEquals = Arrays.equals(arr1, arr2);
 ? ? ? ?System.out.println(isEquals);
?
 ? ? ? ?//2.String toString(int[] a):输出数组信息。
 ? ? ? ?System.out.println(Arrays.toString(arr1));
?
 ? ? ? ?//3.void fill(int[] a,int val):将指定值填充到数组之中。
 ? ? ? ?Arrays.fill(arr1, 10);
 ? ? ? ?System.out.println(Arrays.toString(arr1));
?
 ? ? ? ?//4.void sort(int[] a):对数组进行排序。
 ? ? ? ?Arrays.sort(arr2);
 ? ? ? ?System.out.println(Arrays.toString(arr2));
?
 ? ? ? ?//5.int binarySearch(int[] a,int key)
 ? ? ? ?int[] arr3 = new int[]{-98, -34, 2, 34, 54, 66, 79, 105, 210, 333};
 ? ? ? ?int index = Arrays.binarySearch(arr3, 210);
 ? ? ? ?if (index >= 0) {
 ? ? ? ? ? ?System.out.println(index);
 ? ? ?  } else {
 ? ? ? ? ? ?System.out.println("未找到");
 ? ? ?  }
?
 ? ? ? ?//6. copyof 复制数组
 ? ? ? ?int[] arr4 = {1, 2, 3, 4, 5};
 ? ? ? ?arr4 = Arrays.copyOf(arr4, 6);
 ? ? ? ?for (int i : arr4) {
 ? ? ? ? ? ?System.out.println(i);
 ? ? ?  }
?
 ?  }
}
 

9.Math.random()

  • Math.random()是令系统随机选取大于等于 0.0 且小于 1.0 的伪随机double值

  • 使用方法

    //产生一个[0,1)之间的随机数。
    Math.random();
     
    //返回指定范围的随机数(m-n之间)的公式:
    Math.random()*(n-m)+m;
    或者
    Math.random()*(n+1-m)+m
    // 随机生成a~z之间的字符
    (char)('a'+Math.random()*('z'-'a'+1));
  • Random类生成随机数

  • 除了Math类的Random()方法可以获取随机数之外,还可以Java.util.Random类,可以通过实例化一个Random对象创建一个随机数生成器。

  • 语法

    Random ran=new Random();
  • Random类的实例对象以这种形式实例化对象时,Java编译器以系统当前时间作为随机数生成器的种子,因为每时每刻的时间都不可能相同,所以产生的随机数也不同。如果运行速度太快,也会产生两次运行结果相同的随机数。

  • 可以在实例化Random类对象时,自定义随机数生成器的种子。

Random ran=new Random(seedValue); 
Random类中还提供各种类型随机数的方法:
nextInt():返回一个随机整数(int)
nextInt(int n):返回大于等于0、小于n的随机整数(int)
nextLong():返回一个随机长整型值(long)
nextBoolean():返回一个随机布尔型值(boolean)
nextFloat():返回一个随机浮点型值(float)
nextDouble():返回一个随机双精度型值(double)

文章来源:https://blog.csdn.net/2301_77351901/article/details/135004157
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。