JavaSe语法 -- 数组基础篇

一. 什么是数组

数组可以简单的看成一个相同元素的集合, 在内存中是一段连续的存储空间.

一个数组简易模型
在这里插入图片描述
从上述这个简易模型中, 我们可以得到以下信息:

  1. 数组中存放的元素都是相同类型的
  2. 数组的内存空间是相连的
  3. 每个空间都有一个编号(即常说的数组下标), 从 0 开始

二. 数组的创建

T[ ] 数组名 = new T[N]

T : 表示数组类型
N : 表示数组长度

例如: int [ ] array = new int [ 10 ];
意为创建一个数组名为 array 且 数组元素为 10个 的整形数组

三. 数组的初始化

1.动态初始化 : 在创建数组时, 直接指定数组中的元素个数

int[] array1 = new int[10];

2.静态初始化 : 在创建的时候不指定数组元素个数, 而是直接将具体内容进行指定.

int[] array2 = new int[] {
    
    1,2,3,4};

3.当我们不知道初始化为何值时, 应当初始化赋值为 null, 而不能是其他基础类型
在这里插入图片描述
并且, 在初始化为 null 后, 不能被引用, 也就是一个不指向对象的引用, 否则会空指针异常
在这里插入图片描述

静态初始化有几个特点

  1. 虽然没有指定具体长度, 但是数组的长度在编译器编译时会根据 { } 括号中的元素进行确定
  2. { } 括号中的数据类型必须与 [ ] 前的类型一致
  3. 静态初始化可以省略创建时的 new T [ ]
    int[] array3 = {
    
    1,2,3,4};

对于数组的初始化, 有以下几个特点 :

1.如果数组中存储的元素类型为基本类型, 未初始化则数组中的数据值均为基本类型对应的默认值

例如为 int 类型

int[] array1 = new int[10];
        System.out.println(Arrays.toString(array1));

在这里插入图片描述

例如为 double 类型

double[] array1 = new double[10];
        System.out.println(Arrays.toString(array1));

在这里插入图片描述

2.如果数组中存储的数据类型为引用类型, 则 默认值为 null

String[] array1 = new String[10];
        System.out.println(Arrays.toString(array1));

在这里插入图片描述

3.变量未初始化时, 不允许被使用
在这里插入图片描述

四. 数组是引用类型

在 Java 中, 数组是为引用类型的, 并非由前面 指定的某个类型它则为该类型. 那么, 该如何去理解数组是引用类型这句话呢? 需要从数组在内存中的存储说起.

了解存储前, 需要先了解 JVM (Java Virtual Machine) 是什么? 简单来说 JVM 就是 Java虚拟机

在这里插入图片描述
如果对于内存中的数据不加以区分, 内存管理起来就会非常麻烦, 因此在 JVM 中, 将其大致划分为图中几个数据区

方法区 : 用于存储已被虚拟机加载的类信息、常量、静态变量, 即编译器编译后的代码等数据

堆 : JVM所管理的最大内存区域. 使用new 创建的对象都是在堆上保存

虚拟机栈 : 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了

本地方法栈 : 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量 (源码中的一些 Native 方法)

程序计数器 : 只是一个很小的空间, 保存下一条执行的指令的地址

大致了解了 JVM 那么, 数组是如何在 JVM 中存储的呢?

int[] array = new int[] {
    
    1,2,3,4};
        int a = 10;
        double b = 9.9;

根据上面 JVM 运行时数据区, 数组 array 是 main 方法中的局部变量, a, b 均为局部变量, 因此在 存储在 JVM 的虚拟机栈中(以下简称栈), 而数组的内容属于 new 创建的对象, 位于堆上, 可以画出如下简图 :

在这里插入图片描述
可以看出, array数组在栈上存储的是 数组空间的地址
在这里插入图片描述

对数组是引用类型有一定了解以后, 看看下面这段代码输出什么?

public static void main(String[] args) {
    
    
        int[] array = new int[] {
    
    1,2,3,4};
        fun1(array);
        System.out.println(Arrays.toString(array));
        fun2(array);
        System.out.println(Arrays.toString(array));
    }

    public static void fun1(int[] array) {
    
    
        array = new int[10];
    }

    public static void fun2(int[] array) {
    
    
        array[1] = 99;
    }

这儿很容易犯错, 都以为fun1(array) 过后 输出 array里的内容为 {0,0,0,0,0,0,0,0,0,0}
在这里插入图片描述

你答对了嘛? 为什么呢? 我们通过刚刚的 JVM 运行时数据区来结合理解

在这里插入图片描述
, 在栈上面首先创建了 array 这个变量, 并且在堆上开辟了一块儿空间存储 {1,2,3,4}这组数据. 当我们调用 fun1() 方法时, array 作为形参传入, 此时 fun1() 中的 array 也指向同一块空间 即 0x11, 进入fun1() 方法内部后, array 此时开辟了一块儿新的空间, 因此此时 array 指向新的空间, fun1() 中的 array 存储的就是新的地址 0x33

在这里插入图片描述
当调用方法结束时, 我们打印的是实参的 array, fun1() 方法中的 array 指向 和实参中的array不一样, 并不影响我们输出, 因此输出结果为 {1,2,3,4}

再来看调用 fun2() 方法时, 传入 array 作为形参 此时 fun2() 中的 形参 array 指向同一块儿空间 {1,2,3,4}, 当我们去修改这块空间中的 array[1]元素时, 此时就变成了{1,99, 3,4}, 当我们调用完 fun2() 以后, 该空间中的 array[1] 已经被修改了 再来打印 array 输出时, 结果就为 {1,99,3,4}

在这里插入图片描述

五. 二维数组

1. 二维数组的创建

1 数据类型 [ ] [ ] 数组名 = new 数据类型 [行数] [列数]

2.Java 中二维数组的行数, 列数可用变量来指定

int row = 3;
int line = 3;
int[][] array = new int[row][line];

2. 数组的初始化

1.给数组分配空间大小, 但不能被修改, 在赋值

T[ ][ ] 数组名= new T[行数][列数];

int[][] array1 = new int[3][3];

2.通过 new 给数组直接赋值, 但不给定空间大小

T[ ][ ] 数组名= new T[行数][列数]{ {值1, 值2, 值3}, {值4, 值5, 值6}, {值7, 值8, 值9}};

int[][] array2 = new int[][]{
    
    {
    
    1,2,3},{
    
    4,5,6},{
    
    7,8,9}};
// 编译器会自动计算 array 数组的大小

3.直接赋值, 不予分配空间大小

T[ ][ ] 数组名= { {值1, 值2, 值3}, {值4, 值5, 值6}, {值7, 值8, 值9}};

int[][] array3 = {
    
    {
    
    1,2,3},{
    
    4,5,6},{
    
    7,8,9}};

4.指定行数但不指定列数
T[ ][ ] 数组名= new T[行数][ ]

int[][] array4 = new int[3][];

3. 二维数组是特殊的一维数组

在一维数组中, 我们可以通过Arrays.toString() 方法来直接打印, 那么二维数组是不是也可以?

int[][] array1 = new int[3][3];
        System.out.println(Arrays.deepToString(array1));

在这里插入图片描述

打印的结果却像我们在一维数组中直接输出一维数组看到的地址, 由此可以说明二维数组是特殊的一维数组, 借助前面的 JVM 运行时数据分区图可以知道

在这里插入图片描述
那么, 在 Java 中我们是如何打印二维数组呢? 需要借助到一个方法

        System.out.println(Arrays.deepToString(array1));

在这里插入图片描述

4. 打印二维数组

  1. 常规打印
	int[][] array = new int[row][line];
       	for (int i = 0; i < row; i++) {
    
    
           for (int j = 0; j < line; j++) {
    
    
               System.out.println(array[i][j] + " ");
           }
           System.out.println();
       }

此处并未进行初始化赋值, 因此每个值都是对应基本类型默认值

在这里插入图片描述
对于常规打印循环条件来说, 如果行列数过大, 数是不现实的, 我们可以借助二维数组是特殊的一维数组这一特点, 写出 行, 列之间的关系

for (int i = 0; i < array.length; i++) {
    
    
            for (int j = 0; j < array[i].length; j++) {
    
    
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println(Arrays.toString(array));

此时, array.length 描述的是行数, array[i],length 描述的是 每一行有多少列, 即可得出列数.

在这里插入图片描述

2.迭代器打印

	int row = 3;
	int line = 3;
	int[][] array = new int[row][line];
        for (int[] arr : array) {
    
    
            for (int x : arr) {
    
    
                System.out.print(x+" ");
            }
            System.out.println();
        }

由于二维数组是特殊的一维数组, 因此在第一层循环中, 接收 array 的类型为 一个一维数组, 第二层才是这个一维数组的基本类型

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_68288689/article/details/129589566