Java数组详解

一、数组概述

1.1 为什么需要数组

        如果说现在要求你定义100个整型变量,那么如果按照之前的做法,可能现在定义的的结构如下:
        int i1, i2, i3, ... i100;

        但是这个时候如果按照此类方式定义就会非常麻烦,因为这些变量彼此之间没有任何的关联,也就是说如果现在突然再有一个要求,要求你输出这100个变量的内容,意味着你要编写System.out.println()语句100次。

        如何解决这个问题,Java语言提供了数组(Array)的数据结构,是一个容器可以存储相同数据类型的元素,可以将100个数存储到数组中。

1.2 深入理解数组概念

数组概述:

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

数组相关概念:

        数组名:数组的名称,用于区分不同的数组,数组只有一个名称,即标识符,要符合标识符规范。
        元素类型:数组要存储的元素的数据类型。
        数组元素:向数组中存放的数据/元素。
        元素下标:对数组元素进行编号,元素下标标明了元素在数组中的位置,从0开始;数组中的每个元素都可以通过下标来访问。
        数组长度:数组长度固定不变,避免数组越界。

数组的特点:

        数组是有序排列的集合。
        数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。
        数组的元素的类型,必须一样。
        创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址。
        数组的长度是固定的,长度一旦确定,就不能修改。 
        我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。

数组的分类:

        按照维数:一维数组、二维数组、三维数组、...
                注: 从二维数组开始,我们都称之为多维数组。

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

二、一维数组的使用

2.1 一维数组的声明和初始化

声明数组的语法格式1:
        元素类型[] 数组名 = new 元素类型[元素个数或数组长度];

声明数组的语法格式2:
        元素类型[] 数组名 = new 元素类型[]{元素,元素,……};

声明一个变量就是在内存空间划出一块合适的空间,声明一个数组就是在内存空间划出一串连续的空间。

注:
        []在元素类型后 或 数组名后都可以。
        Java语言中声明数组时不能指定其长度(数组中元素的数), 例如: int a[5]; //非法

数组初始化分类:
        动态初始化:数组声明且为数组元素分配空间与赋值的操作分开进行
                int[] arr = new int[3];
                arr[0] = 3;
                arr[1] = 9;
                arr[2] = 8
    
        静态初始化:在定义数组的同时就为数组元素分配空间并赋值。
                int arr[] = new int[]{ 3, 9, 8}; 或 int[] arr = {3,9,8};

new关键字:
        Java中使用关键字new来创建数组。
        定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;

示例代码:

// 变量声明
int num;
// 变量初始化
num = 10;
// 变量声明 + 初始化
int id = 1001;

// 数组声明
int[] ids;
// 静态初始化:数组的初始化和数组元素的赋值操作同时进行
ids = new int[]{1001,1002,1003,1004};
// 动态初始化:数组的初始化和数组元素的赋值操作分开进行
String[] names = new String[5];

// 错误的写法:
// int[] arr1 = new int[];
// int[5] arr2 = new int[5];
// int[] arr3 = new int[3]{1,2,3};

//也是正确的写法:
int[] arr4 = {1,2,3,4,5};// 类型推断

// 总结:数组一旦初始化完成,其长度就确定了。

2.2 一维数组的使用

        数组元素的引用方式:数组名[数组元素下标],如boy[0],boy[1]等。
                数组元素下标可以是整型常量或整型表达式。如a[3] , b[i] , c[6*i];
                数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 —>n-1;如int a[]=new int[3]; 可引用的数组元素为a[0]、a[1]、a[2]

        需要注意的是索引从0开始,到数组的长度-1结束。

示例代码:

// 创建一个长度为5的数组,用来存储学生的姓名
String[] names = new String[5];

// 给数组的指定位置赋值
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
names[3] = "马六";
names[4] = "田七";
// 数组长度5,下标从0开始,到4结束,使用下标5会抛出异常。
// names[5] = "钱八";

// 调用数组的指定位置的元素
System.out.println("下标2的学生的姓名是:"+names[2]);

2.3 获取数组的长度

        每个数组都有一个属性length指明它的长度,例如:a.length 指明数组a的长度(元素个数)。

        数组一旦初始化,其长度是不可变的。

示例代码:

int[] ids = new int[]{1001,1002,1003,1004};
String[] names = new String[5];

System.out.println(names.length);// 5
System.out.println(ids.length);// 4

2.4 一维数组的遍历

        通过for循环,结合下标索引实现数组的遍历。

示例代码:

String[] names = {"张三","李四","王五","马六","田七"};
/*System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);
System.out.println(names[4]);*/

for(int i = 0;i < names.length;i++){
    System.out.println(names[i]);
}

增强for循环:

        foreach语句是java5的新特征之一,在遍历数组、集合方面,foreach为开发人员提供了极大的方便。
        foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本。

        foreach的语句格式:
                for(元素类型 元素变量x : 数组/集合){
                        引用了x的java语句;
                }

String[] names = {"张三","李四","王五","马六","田七"};

for(String name : names){
    System.out.println(name);
}

练习题:

        对数据进行处理:计算5位学生的平均分

int [ ] score = {60, 80, 90, 70, 85};
double avg;
avg = (score[0] + score[1] + score[2] + score[3] + score[4])/5;

// 上述写法虽说也可以实现,但是如果10个或100个学生呢?
// 通过遍历数组叠加求和,最后除以数组长度得到平均分。
int [ ] score = {60, 80, 90, 70, 85};
int sum = 0;
for(int i = 0; i < score.length; i++){
     sum += score[i];
}
double avg = sum / score.length; 

2.5 数组元素的默认初始值

        数组是引用类型,它的元素相当于类的成员变量,因此数组一经分配空间,其中的每个元素也被按照成员变量同样的方式被隐式初始化。
    
        对于基本数据类型而言,默认初始化值各有不同。
        对于引用数据类型而言,默认初始化值为null(注意与0不同!)

数组元素类型元素默认初始值
byte0
short0
int0
long0L
float0.0F
double0.0
char0 或写为:’\u0000’(表现为空)
booleanfalse
引用类型null

示例代码:

int[] arr = new int[4];
for(int i = 0;i < arr.length;i++){
    System.out.println(arr[i]);
}
System.out.println("------------------------");

short[] arr1 = new short[4];
for(int i = 0;i < arr1.length;i++){
    System.out.println(arr1[i]);
}
System.out.println("------------------------");
float[] arr2 = new float[5];
for(int i = 0;i < arr2.length;i++){
    System.out.println(arr2[i]);
}

System.out.println("------------------------");
char[] arr3 = new char[4];
for(int i = 0;i < arr3.length;i++){
    System.out.println("----" + arr3[i] + "----");
}

if(arr3[0] == 0){
    System.out.println("char类型的默认值是0,但是表现为空");
}

System.out.println("------------------------");
boolean[] arr4 = new boolean[5];
System.out.println(arr4[0]);

System.out.println("------------------------");
String[] arr5 = new String[5];
System.out.println(arr5[0]);
if(arr5[0] == null){
    System.out.println("引用类型的默认类型是null,不是null字符串!");
}

2.6 一维数组的内存解析

内存的简化结构:

        栈(stack):存放基本类型的变量数据、局部变量和对象的引用,但对象本身不存放在栈中。

        堆(heap):存放由new创建的对象和数组以及对象的实例变量。

        静态存储区(static storage):又叫方法区:包含的都是在整个程序中永远唯一的元素,如class,static变量。
        常量存储区(constant storage):常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。
        静态区/静态域(static storage):随着类的加载而加载并初始化,存在于方法区内存中的字节码文件的静态区域中。

 内存解析:

 地址引用:

        数组属于引用型变量,因此两个相同类型的数组且具有相同的引用,它们就有完全相同的元素。

  例如,对于int a[] = {1,2,3}, b[ ]= {4,5};数组变量a和b分别存放着引用0x35ce36和0x757aef。 

        如果使用了下列赋值语句(a和b的类型必须相同)a=b;那么,a中存放的引用和b的相同,这时系统将释放最初分配给数组a的元素,使得a的元素和b的元素相同。

三、多维数组的使用

        Java 语言里提供了支持多维数组的语法。

        如果说可以把一维数组当成几何中的线性图形,那么二维数组就相当于是一个表格,像Excel中的表格一样。

        二维数组本质上是以数组作为数组元素的数组,即“数组的数组”,其实,从数组底层的运行机制来看,其实没有多维数组。

3.1 二维数组的声明和初始化

声明二位数组的语法格式1(动态初始化):int[][] arr = new int[3][2];
        定义了名称为arr的二维数组
        二维数组中有3个一维数组
        每一个一维数组中有2个元素
        一维数组的名称分别为arr[0], arr[1], arr[2]
        给第一个一维数组1下标位赋值为78写法是:arr[0][1] = 78;

声明二位数组的语法格式1(动态初始化):int[][] arr = new int[3][];
        二维数组中有3个一维数组。
        每个一维数组都是默认初始化值null (注意:区别于格式1)
        可以对这个三个一维数组分别进行初始化
        arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];
        注:
                int[][]arr = new int[][3]; //非法

声明二位数组的语法格式3(静态初始化):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;

注意特殊写法情况:int[] x,y[]; x是一维数组,y是二维数组。
Java中多维数组不必都是规则矩阵形式。

示例代码:

// 二维数组的声明和初始化
int[] arr = new int[]{1,2,3};//一维数组
// 静态初始化
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
// 动态初始化1
String[][] arr2 = new String[3][2];
// 动态初始化2
String[][] arr3 = new String[3][];
// 错误的情况 
// String[][] arr4 = new String[][4];
// String[4][3] arr5 = new String[][];
// int[][] arr6 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};

//也是正确的写法:
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};

3.2 二维数组的使用

        数组元素的引用方式:数组名[一维数组下标][二维数组下标],如boy[0][1],boy[1][1]等。

        需要注意的是索引从0开始,到数组的长度-1结束。

示例代码:

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

String[][] arr2 = new String[3][2];

String[][] arr3 = new String[3][];

System.out.println(arr1[0][1]);// 2
System.out.println(arr2[1][1]);// null

// 这样调用报错,因为没有给arr3[1]进行赋值操作,出现空指针异常
// System.out.println(arr3[1][0]);
arr3[1] = new String[4];
System.out.println(arr3[1][0]);

3.3 获取数组的长度

示例代码:

int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
System.out.println(arr4.length);// 3
System.out.println(arr4[0].length);// 3
System.out.println(arr4[1].length);// 4

3.4 二维数组的遍历

规定:二维数组分为外层数组的元素,内层数组的元素
        int[][] arr = new int[4][3];
        外层元素:arr[0],arr[1]等
        内层元素:arr[0][0],arr[1][2]等
        System.out.println(arr[0]);//[I@15db9742 
        System.out.println(arr[0][0]);//0

示例代码:

//声明二维数组并赋值	int arr[][] = {{},{},{}}
int arr[][] = {{1,2,3},{11,12,13,14},{22,33,44,55,66,77},{1}};

// arr  是数组
// arr[i]	还是数组
for(int i = 0;i < arr.length;i++) {
    int ewArr[] = arr[i]; //一维数组里面的每个数组
    for(int j = 0;j < ewArr.length;j++) {
        System.out.print(ewArr[j]+"\t");
    }
    System.out.println();
}

System.out.println("--------------------------------");

// 增强for循环遍历
for(int ewArr[] :arr) {
    for(int x : ewArr) {
        System.out.print(x+"\t");
    }
    System.out.println();
}

3.5 数组元素的默认初始值

        针对于初始化方式一:比如:int[][] arr = new int[4][3];
                外层元素的初始化值为:地址值
                内层元素的初始化值为:与一维数组初始化情况相同
        
        针对于初始化方式二:比如:int[][] arr = new int[4][];
                外层元素的初始化值为:null

示例代码:

int[][] arr = new int[4][3];
System.out.println(arr[0]);//[I@15db9742 
System.out.println(arr[0][0]);//0

// System.out.println(arr);//[[I@6d06d69c

System.out.println("*****************");
float[][] arr1 = new float[4][3];
System.out.println(arr1[0]);//地址值
System.out.println(arr1[0][0]);//0.0

System.out.println("*****************");

String[][] arr2 = new String[4][2];
System.out.println(arr2[1]);//地址值
System.out.println(arr2[1][1]);//null

System.out.println("*****************");
double[][] arr3 = new double[4][];
System.out.println(arr3[1]);//null
// System.out.println(arr3[1][0]);//报错

3.6 二位数组的内存解析

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是波哩个波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值