回顾
多态是同一个行为,具有不同的表现形式。
多态的实现方式
多态存在的必要条件
继承:重写以继承为基础,继承以封装为基础
重写:子类重写父类中的方法
向上造型
引入
那今天我们再来看一下引用类型数组。那什么是引用类型数组呢,单看“引用类型数组”这六个字信息量就是非常大的,可以总结出两点
引用类型数组
所以呢,今天要把数组当成一个对象来看待,主要来学习一下数组当做对象的本质,而且另外数组本身就是一组类型相同的变量的组合,所以关注数组同样也样像关注普通变量一样,了解他的声明和初始化。
如果最后还有时间咱们来看一下二维数组。
好的,那接下来呢我们就来深入学习一下引用类型数组,首先来看一下数组的本质
一、数组是对象
数组的本质有两点
比如:实例化一个int类型的数组,其中包含三个元素。保存在变量arr中。
int[] arr = new int[3];
其实,创建的结果在内存中是这样的,首先会有一个int类型的数组名叫arr,因为它是数组类型,所以arr是引用类型变量,将来保存的,不是数据本身,而仅仅是数组对象的地址。然后程序运行new运算符就会在内存中创建一个数组对象,其中定义三个int类型元素,因为没有给具体值,所以程序运行的时候,构造方法会默认给一个初始值,int类型的默认值是0.创建完数组对象,这个对象一定会有一个内存地址,假设为0x50 ,然后这个地址就会用=保存在arr变量中。

所以呢,刚刚说的大一堆咱们可以提炼出三点内容:
二、引用类型数组的声明
我们学了数组,又学了面向对象之后,我们就可以把数组和面向对象结合起来使用
其实,数组中的元素可以是任意类型,当然也包括引用类型,也就是说数组中的元素不仅仅只能放数据,而且还能放任何一种活灵活现的对象
如果数组中的元素是引用类型,那么数组就称之是引用类型数组。
那什么时候使用引用数组呢,只要希望分组管理多个对象,就要使用引用类型数组
事实上,现实中,数组中不应该只放一种类型的数据或者元素,数组中的元素很可能是一个具有丰富属性和行为的对象。
我知道男孩子都爱打游戏,那我们就拿英雄联盟为例。
比如说,程序需要我们创建3个“英雄联盟”中的游戏人物并组成一队
如果想要创建这五个人物对象,肯定首先得要先声明一个人物类Character,用来封装人物的统一属性,类中应该包含3个属性,分别是名字name,生命值hp,伤害值dps
这个类是用来封装人物类的属性,我们在学构造的时候讲过大部分的类为方便初始化成员变量,都需要我们自己定义两个构造方法,一个带参构造,一个空的无参构造。
好的,只要需要分组管理对象,就要使用数组,而游戏中大家要创建的3个人物,都是Character类型的对象,所以接下来咱们在测试类中来定义一个能容纳3个Character对象的数组。
Character[] chs = new Character[3];
代表创建了3个人物对象数组。那如果这时候程序运行的时候,和基本数据类型的数组一样,都会有一个数组对象,其中包含3个成员变量,然后呢都会将数组的内存地址保存到数组变量chs中,这里最大的不同发生在数组中的每个成员变量里。
基本类型的数组中,每个类型都是基本类型有默认的初始值是0,而引用类型数组的默认值为null。表示现在还没有创建人物对象。

三、引用类型数组的初始化
如果要让每一个元素都指向具体的对象,需要针对每一个数组元素分别进行new运算实例化对象,这就相当于游戏中你要专门挑选一个格子把你的人物放进来。
chs[0] = new Character(“金克丝”,380,50);
chs[1] = new Character(“奎因”,390,48);
chs[2] = new Character(“阿狸”,514.4, 53.04);
数组中的元素下标都从0开始,所以中括号0代表第一个元素。new 创建一个Character类型的对象。
如果程序执行到这的时候,引用类型的数组每一个元素都是一个引用类型的变量,仅保存对象地址,不保存对象本身,程序执行的时候,每new一个都会创建一个人物对象。

那下面呢,我们就试着遍历一下数组,通过数组地址来引用每个人物对象。遍历数组和以前一样,同样使用for循环,int i = 0;i<数组的长度,i++,然后在循环当中调用输出的printInfo方法。如果没有特殊情况,数组的遍历到哪都这么写。
for (int i = 0; i < chs.length; i++) {
chs[i].printInfo();
}
好的,那关于引用类型数组就先说到这里,以后引用类型数组的用途是非常广泛的,因为以后很少会有数组中仅保存一种数值的情况,通常都是将多个对象组织在数组结构中,理解引用类型数组,大家主要理解其实数组中并没有保存对象的本身,而是仅保存对象的地址,通过地址指向实际对象而已。但是使用时,使用元素就等效于直接使用元素中地址所指向的实际对象。
二维数组
定义
下面呢,我们来看一种更加高大上的数组类型二维数组,既然数组中的元素可以是任意类型,那同样也可以是数组类型,如果数组中的元素仍然是一个数组的话,那么它就是一个二维数组。
所谓二维在现实世界中其实就是一个横行数列的结构,所以今后呢,只要是看到横行数列的表现形式,就使用二维数组。比如说大家经常看的日历,再者说,大家去超市买鸡蛋的时候有没有观察过鸡蛋是怎么摆的?是不是先把鸡蛋水平放在一层盒子里,然后再摞几层啊。那么在程序中,
他就可以用二维数组来表示,咱们就拿超市摞鸡蛋的例子来看。
案列
首先,要求每层都放5个鸡蛋,要摞3层,那首先我们就得准备3个能放5个鸡蛋的包装盒,分别装入5个鸡蛋。我们直接在main方法中完成
char [] box1 = new char[] {'蛋','蛋','蛋','蛋','蛋'};
char [] box2 = new char[] {'蛋','蛋','蛋','蛋','蛋'};
char [] box3 = new char[] {'蛋','蛋','蛋','蛋','蛋'};
首先,分别创建3盒鸡蛋,每盒装5个,这是个体力活,我就直接复制就可以,这时候这三盒鸡蛋是随机摆放的,但是现在我要求这三盒摞在一起。那就的需要有一个可以容纳这三个盒子的数组,既然是数组那就得有数据类型和元素个数,来观察一下,每个盒子的类型都是一个char类型的数组,所以我们就可以把char类型的数组当成盒子的数据类型。
所以我们可以定义一个可以容纳三个盒子对象的数组,三个盒子都是char类型数组
char[][]rack =new char[][]{box1,box2,box3};
前面的char[]是数据类型,那么程序运行的时候他的内存中会发生什么情况呢,咱们还是先来看一下。理解了二维数组的结构,以后才能运用自如。
首先我们创建了三个二维数组对象,分别将地址保存在box1,box2,box3中,
后来我们又发现需要将三个数组统一起来管理,不能散着放。只要需要成组的管理数据就要使用数组。所以我们又创建了一个rack数组表示一个货架,

在实例化数组对象的同时,使用box1,box2,box3,中的值初始化数组rack的每个元素,在Java中任何情况下都是值传递,所以rack数组中得到的其实是box1,box2,box3的地址值,不是数组对象本身,得到地址后的rack中的三个元素就分别指向了三个具体的数组对象地址,在程序中,引用类型变量只保存地址所以不会真的把鸡蛋保存在货架上,都是通过每个元素中的地址指向数组中的对象。

遍历二维数组
遍历数组使用for循环,同样,遍历二维数组,是要使用嵌套for循环。
// 遍历rack中的每个元素,得到每个box对象的地址
for (int i = 0; i < rack.length; i++) {
// rack[i]表示rack数组中下标为i的元素中保存的地址同时也指向具体的一个box对象
// 每得到一个box对象的地址就进一步遍历其中的每个元素
for (int j = 0; j < rack[i].length; j++) {
// 可以理解为是货架上第i层,第j个元素的内容
System.out.print(rack[i][j] + ",");
}
// 最后,每打印一行,就输出一次换行,准备打印下一组元素
System.out.println();
}
我说明一下昂rack[i][j]其实就可以理解为是第i层的第j个元素,只不过这个i和j都是从0开始,通常这种写法都是用来访问二维数组中任意位置的元素。
其实二维数组经常用于表示表,表中的信息以行和列的形式组织,第一个下标代表元素所在的行,第二个下标代表元素所在的列。声明的时候我们可以直接这样定义
•数据类型[][] 数组变量=new 数组类型[行数][列数];
•创建3行5列的数组char [][] arr =new char[3][5];
总结
如果数组中的元素是一个引用类型的话,那这个数组就叫引用类型数组,引用类型数组本质上是一个对象,数组变量里面存储的是一个对象地址,用于指向数组本身,而二维数组呢大家可以这么理解,就是数组里套了一个数组对象。遍历二维数组使用双重for循环。
标签: