大数据技术分享 大数据技术分享
  • 数学基础
  • 数学进阶
  • 编程入门
  • 电子基础
  • 编译原理
  • 数据结构与算法
  • 软件工程
  • 体系结构
  • 操作系统
  • 计算机网络
  • 计算机图形学
  • 设计模式
  • 并行与分布式系统
  • 计算机系统安全
  • Java基础
  • Java集合
  • Java并发
  • Java虚拟机
  • Linux
  • Shell
  • JDBC
  • Maven
  • Nginx
  • Git
  • Web开发
  • Docker
  • Zookeeper
  • Scala
  • Sqoop
  • Flume
  • Kafka
  • 数据清洗
  • HDFS
  • MySQL
  • HBase
  • Redis
  • ClickHouse
  • Hadoop
  • Hive
  • Spark
  • Flink
  • Java面试题
  • 大数据面试题
  • Java项目
  • 大数据项目
  • 推荐系统
  • 机器学习
  • 深度学习
  • 闲聊
  • 读书笔记
归档
  • 数学基础
  • 数学进阶
  • 编程入门
  • 电子基础
  • 编译原理
  • 数据结构与算法
  • 软件工程
  • 体系结构
  • 操作系统
  • 计算机网络
  • 计算机图形学
  • 设计模式
  • 并行与分布式系统
  • 计算机系统安全
  • Java基础
  • Java集合
  • Java并发
  • Java虚拟机
  • Linux
  • Shell
  • JDBC
  • Maven
  • Nginx
  • Git
  • Web开发
  • Docker
  • Zookeeper
  • Scala
  • Sqoop
  • Flume
  • Kafka
  • 数据清洗
  • HDFS
  • MySQL
  • HBase
  • Redis
  • ClickHouse
  • Hadoop
  • Hive
  • Spark
  • Flink
  • Java面试题
  • 大数据面试题
  • Java项目
  • 大数据项目
  • 推荐系统
  • 机器学习
  • 深度学习
  • 闲聊
  • 读书笔记
归档
  • Java基础

    • Java之变量与基本数据类型
    • Java之运算符与流程控制
    • Java数组详解
      • 概述
      • 一维数组
        • 声明
        • 初始化
        • 使用
        • 遍历
        • 默认值
        • 内存分析
        • Java虚拟机的内存划分
        • 一维数组在内存中的存储
      • 多维数组
        • 概述
        • 声明和初始化
        • 长度和角标
        • 二维数组的遍历
        • 内存解析
    • 数组中这些常用算法你掌握了吗?
    • Java面向对象的内存分析
    • Java面向对象之类的成员
    • Java面向对象的三大特征
    • Java面向对象中的关键字
    • Java中Object类的理解和使用
  • Java集合

  • Java并发

  • Java虚拟机

  • Java
  • Java基础
高飞
2020-09-09
目录

Java数组详解

今天继续更新Java系列,下面看下Java的数组,会结合内存分析来讲解数组。

# 概述

为什么需要数组呢,比如,需要统计公司员工的工资情况,这个时候用变量的话就需要定义好多个变量,这样会很麻烦,因此数组就很适合这种场景。

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

数组的特点:

  • 数组本身是引用数据类型,但数组中的元素可以是任何数据类型
  • 创建数组对象会在内存中开辟一整块连续的空间,占据空间的大小取决于数组的长度和数组中元素的类型
  • 数组中的元素在内存中是依次紧密排列的有序的
  • 数组一旦初始化完成,其长度就是确定的,而数组的长度一旦确定就不能修改
  • 可以直接通过下标的方式调用指定位置的元素
  • 数组名中引用的是这块连续空间的首地址

# 一维数组

# 声明

格式:

//推荐
元素的数据类型[] 一维数组的名称;
//不推荐
元素的数据类型  一维数组名[];
1
2
3
4

举例:

int[] arr;
int arr1[];
String[] arr3;  //引用类型变量数组
1
2
3

数组的维度:在Java中数组的符号是[],[]表示一维,[][]表示二维。

数组的元素类型:可以是任意的Java的数据类型。

数组名:数组名也是变量名,按照变量的命名规范来命名。

注:Java中声明数组时不能指定长度(数组中元素的个数), 例如int a[5];是非法的。

# 初始化

静态初始化: 数组变量的初始化和数组元素的赋值操作同时进行称为静态初始化,本质是用静态数据为数组初始化,此时数组的长度由静态数据的个数决定。

格式1:

数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,...};
或者
数据类型[] 数组名;
数组名 = new 数据类型[]{元素1,元素2,元素3,...}; //数组本身是引用数据类型,所以要用new创建数组实体
1
2
3
4

举例:

int[] arr = new int[]{1,2,3,4,5};
//或者
int[] arr;
arr = new int[]{1,2,3,4,5};
1
2
3
4

格式2:

数据类型[] 数组名 = {元素1,元素2,元素3...}; //必须在一个语句完成,不能分成两个语句
1

举例:

int[] arr = {1,2,3,4,5};
1

动态初始化: 数组变量的初始化和数组元素的赋值操作分开进行称为动态初始化。动态初始化中只确定了元素的个数,而元素值此时只是默认值,真正的数据需要后面单独一个个赋值。

格式:

数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度];
或者
数组存储的数据类型[] 数组名字;
数组名字 = new 数组存储的数据类型[长度];
1
2
3
4

注:数组长度一旦指定不可更改。

举例:

int[] arr = new int[5];
//或者
int[] arr;
arr = new int[5];
1
2
3
4

# 使用

长度:每个数组都有一个属性length来指明它的长度,每个数组一旦初始化长度就是确定且不可变的。

引用:每个存储到数组的元素都会自动拥有一个从0开始的编号,这个编号称为数组索引或下标,可以通过数组的索引或下标访问数组中的元素。

# 遍历

将数组中每个元素分别获取出来就是遍历,for循环与数组的遍历是绝配。

举例:

public class ArrayTest {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        //打印数组的长度,输出结果是5
        System.out.println("数组的长度:" + arr.length);
        //遍历输出数组中的元素
        System.out.println("数组的元素有:");
        for(int i=0; i<arr.length; i++){
            System.out.println(arr[i]);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 默认值

数组是引用类型,当使用动态初始化方式创建数组时,元素值只是默认值。

对于基本数据类型,默认初始化值各有不同,对于引用数据类型,默认初始化值为null。

# 内存分析

# Java虚拟机的内存划分

为了提高运算效率,对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

区域名称 作用
虚拟机栈 用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完自动释放。
堆内存 存储对象(包括数组对象),new创建的都存储在堆内存。
方法区 存储已被虚拟机加载的类信息、常量、(静态变量)、即时编译器编译后的代码等数据。
本地方法栈 当程序中调用了native的本地方法时,本地方法执行期间的内存区域
程序计数器 程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址

# 一维数组在内存中的存储

一个一维数组内存图:

public static void main(String[] args) {
  	int[] arr = new int[3];
  	System.out.println(arr); //[I@5f150435
}
1
2
3
4

程序执行流程:

  1. main方法进入方法栈执行。
  2. 创建数组,JVM会在堆内存中开辟空间,存储数组。
  3. 数组在内存中会有自己的内存地址,以十六进制数表示。
  4. 数组中有3个元素,默认值为0。
  5. JVM将数组的内存首地址赋值给引用类型变量arr。
  6. 变量arr保存的是数组内存中的地址,而不是一个具体数值,因此称为引用数据类型。

数组下标为什么从0开始:因为第一个元素距离数组首地址间隔0个单元格。

两个一维数组内存图:

public static void main(String[] args) {
    int[] arr = new int[3];
    int[] arr2 = new int[2];
    System.out.println(arr);
    System.out.println(arr2); //两个数组独立
}
1
2
3
4
5
6

两个变量指向一个一维数组:

public static void main(String[] args) {
    //定义数组,存储3个元素
    int[] arr = new int[3];
    //数组索引进行赋值
    arr[0] = 5;
    arr[1] = 6;
    arr[2] = 7;
    //输出3个索引上的元素值
    System.out.println(arr[0]);
    System.out.println(arr[1]);
    System.out.println(arr[2]);
    //定义数组变量arr2,将arr的地址赋值给arr2
    int[] arr2 = arr;
    arr2[1] = 9;
    System.out.println(arr[1]);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

两个数组变量本质上代表同一个数组。

# 多维数组

# 概述

Java语言提供了支持多维数组的语法,如果把以为数组当成几何中的线性图形,那么二维数组就相当于一个表格。

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

其实从数组底层的运行机制来看,没有多维数组。

# 声明和初始化

声明:

//推荐
元素的数据类型[][] 二维数组的名称;
//不推荐
元素的数据类型  二维数组名[][];
//不推荐
元素的数据类型[]  二维数组名[];
1
2
3
4
5
6

举例:

public class Test20TwoDimensionalArrayDefine {
    public static void main(String[] args) {
        //存储多组成绩
        int[][] grades;
        //存储多组姓名
        String[][] names;
    }
}
1
2
3
4
5
6
7
8

注:对于int[] x, y[];,其中x是一维数组,y是二维数组。

静态初始化: 格式:

int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};
1

对于二维数组的长度,比如上面第三个一维数组的长度可以用arr[2].length来表示。 举例:

int[][] arr = {{1,2,3},{4,5,6},{7,8,9,10}}; //声明与初始化必须在一句完成
int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};
int[][] arr;
arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};
1
2
3
4

动态初始化: 格式1:规则二维表,每一行的列数都是相同的。

//确定行数和列数
元素的数据类型[][] 二维数组名 = new 元素的数据类型[m][n];
//其中m:表示这个二维数组有多少个一维数组,或者说一共二维表有几行
//其中n:表示每一个一维数组的元素有多少个,或者说每一行共有一个单元格
//此时创建完数组,行数、列数确定,而且元素也都有默认值
//再为元素赋新值
二维数组名[行下标][列下标] = 值;
1
2
3
4
5
6
7

格式2:不规则二维表,每一行的列数不一样。

//先确定总行数
元素的数据类型[][] 二维数组名 = new 元素的数据类型[总行数][];
//此时只是确定了总行数,每一行里面现在是null
//再确定每一行的列数,创建每一行的一维数组
二维数组名[行下标] = new 元素的数据类型[该行的总列数];
//此时已经new完的行的元素就有默认值了,没有new的行还是null
//再为元素赋值
二维数组名[行下标][列下标] = 值;
1
2
3
4
5
6
7
8

# 长度和角标

  • 二维数组的长度或行数可表示为二维数组名.length
  • 二维数组的某一行可表示为二维数组名[行下标],此时相当于获取其中一组数据,它本质上是一个一维数组
  • 某一行的列数可表示为二维数组名[行下标].length,因为二维数组的每一行是一个一维数组
  • 某一个元素可表示为二维数组名[行下标][列下标],即先确定行/组,再确定列

# 二维数组的遍历

格式:

for(int i=0; i<二维数组名.length; i++){ //二维数组对象.length
    for(int j=0; j<二维数组名[i].length; j++){ //二维数组行对象.length
        System.out.print(二维数组名[i][j]);
    }
    System.out.println();
}
1
2
3
4
5
6

举例:

public class Test23TwoDimensionalArrayIterate {
    public static void main(String[] args) {
        //存储3个小组的学员的成绩,分开存储,使用二维数组。
        int[][] scores = {
                {85,96,85,75},
                {99,96,74,72,75},
                {52,42,56,75}
        };
        System.out.println("一共有" + scores.length +"组成绩.");
        for (int i = 0; i < scores.length; i++) {
            System.out.print("第" + (i+1) +"组有" + scores[i].length + "个学员,成绩如下:");
            for (int j = 0; j < scores[i].length; j++) {
                System.out.print(scores[i][j]+"\t");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 内存解析

二维数组本质上是元素类型是一维数组的一维数组。

int[][] arr = {
    {1},
    {2,2},
    {3,3,3},
    {4,4,4,4},
    {5,5,5,5,5}
};
1
2
3
4
5
6
7

//声明二维数组,并确定行数和列数
int[][] arr = new int[4][5];
//确定元素的值
for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr.length; j++) {
        arr[i][j] = i + 1;
    }
}
1
2
3
4
5
6
7
8

//声明一个二维数组,并且确定行数
//因为每一行的列数不同,这里无法直接确定列数
int[][]  arr = new int[5][];
//确定每一行的列数
for(int i=0; i<arr.length; i++){
    arr[i] = new int[i+1];
}
//确定元素的值
for(int i=0; i<arr.length; i++){
    for(int j=0; j<arr[i].length; j++){
        arr[i][j] = i+1;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

最后,今天的内容就到这里,Java教程持续更新中,喜欢的话点个关注吧,下篇见!

🎁 公众号

小伙伴们大家好,上方扫码关注公众号「大数据技术开发」,与你分享我的成长历程与技术感悟~

Java之运算符与流程控制
数组中这些常用算法你掌握了吗?

← Java之运算符与流程控制 数组中这些常用算法你掌握了吗?→

最近更新
01
知识体系总览
02-27
02
读书笔记
02-21
03
深度学习
02-20
更多文章>
Theme by Vdoing | Copyright © 2019-2023 码农高飞 | 豫ICP备2021025399号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式