JavaSe语法 -- 数组基础篇

简介: JavaSe语法 -- 数组基础篇

一. 什么是数组



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

一个数组简易模型

e2412b3f544e4177b7ae500499ba720a.png


从上述这个简易模型中, 我们可以得到以下信息:

  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, 而不能是其他基础类型

3c2f93d978754b6aad097f86d56d8fa6.png


并且, 在初始化为 null 后, 不能被引用, 也就是一个不指向对象的引用, 否则会空指针异常

5ad49c9d838d4e42a7ff8e12e6802071.png


静态初始化有几个特点

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


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


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


例如为 int 类型

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


315fa2c08a5c4d6f86a6711624f9fd05.png


例如为 double 类型

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

809e0ce7d566470993f42c00eb738f46.png


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

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


7775886953fe433a8ef778c8c921507d.png


3.变量未初始化时, 不允许被使用

49eae929cace4aedb289215f9aabb7d9.png


四. 数组是引用类型



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


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

89b045d399fe4d1a8741a82fe4a606a1.png


如果对于内存中的数据不加以区分, 内存管理起来就会非常麻烦, 因此在 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 创建的对象, 位于堆上, 可以画出如下简图 :

b6cdbf605b6447d3aea65c2b00aeea29.png

可以看出, array数组在栈上存储的是 数组空间的地址

80f89ae9cecc42d5b4f87e40ae9a74a5.png


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


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}

5e413eb909ed47f59c853b0a0074d76e.png


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

62e7406ff66f451896e141293b19d8d2.png


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

b21f5a95f7804c6288b05cf7273a7130.png


当调用方法结束时, 我们打印的是实参的 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}

1f5e7f7337cf4f0c9ce4ae62aa7cb474.png


五. 二维数组



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));

ffb4aefb70244eb1a982bd6fca0adc5d.png

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


46e41d8b1b0d486387d65c2edcbe0518.png


那么, 在 Java 中我们是如何打印二维数组呢? 需要借助到一个方法

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


a58dae22a3c8454fa28144c2422d6f7c.png


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();
       }


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

a16f7a9fcb894db7b1de9f228476be0f.png


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

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 描述的是 每一行有多少列, 即可得出列数.

3834090388ff4814a848af2cdae01ece.png


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 的类型为 一个一维数组, 第二层才是这个一维数组的基本类型


b5f0fef1ab174d11add81e29d773e84c.png

相关文章
|
10月前
|
存储 Java 编译器
数组的定义与使用【JavaSE】
数组的定义与使用【JavaSE】
29 0
|
11月前
|
存储 机器学习/深度学习 Java
【javaSE】 数组的定义与使用
【javaSE】 数组的定义与使用
|
存储 Java C语言
教你精通JavaSE语法->第三章、运算符
计算机的最基本的用途之一就是执行数学运算,即:对操作数进行操作时的符号,不同运算符操作的含义不同。-------->复习或初学Java语法
64 0
|
3月前
|
存储 机器学习/深度学习 Java
【Java SE语法篇】6.数组
【Java SE语法篇】6.数组
|
3月前
|
Java
JavaSE基础篇:枚举的高级用法示例
JavaSE基础篇:枚举的高级用法示例
|
3月前
|
存储 Java 编译器
JavaSE学习--数据类型和运算符
JavaSE学习--数据类型和运算符
74 0
|
8月前
|
存储 机器学习/深度学习 Java
【JavaSE】数组的定义与使用
【JavaSE】数组的定义与使用
|
9月前
|
存储 Oracle Java
【JavaSE语法】数据类型与变量
【JavaSE语法】数据类型与变量
40 0
|
存储 机器学习/深度学习 搜索推荐
教你精通JavaSE语法之第六章、数组的使用
JavaSE数组的知识点介绍,适用于初学者和有一定经验的学生进行学习和复习。
82 0
|
Java 编译器
教你精通JavaSE语法第五章、方法的使用
JavaSE的方法的使用详细介绍,适用于初学者和有一定基础的学生对方法的概念复习和细节上的掌握
41 0