* 掌握数组定义及初始化,以及数组操作
* 掌握对数组操作的内存分析,
* 清楚多维数组的本质,内存分析和操作方式
* 掌握数组新特性中foreach和可变参数的使用方式和注意点,
* 掌握数组元素拷贝,线性查找及二分查找法
* 掌握冒泡和选择排序的原理,特点和效率
* 理解封装工具类的好处,并且熟练使用数组工具类Arrays。
“先去学会制造工具,再去使用工具,才会对工具更深的理解和把握”
“文档在手,天下我有”
想法总结
· 对于陌生的情况,采取逐步推导的方式,将步骤细分,查看推导的演变和规律,在规律中探究变与不变,然后形成基本的思路
· 技术学习从why出发,了解what,熟悉how,思考where,最终回顾why与what之间的本质联系
· 面对陌生的技术,尝试从文档开始,利用对技术从0到1的理解
数组
· why: 当需要使用一堆相同类型的变量数据,针对这堆数据进行操作避免声明过多地变量,提高操作效率
· what: 按照一定顺序将同个数据类型的数据排列在一起的集合
· where: 操作大量同类型,相同结构的数据时使用
数组为引用类型的一种,因此数组数据存储在堆的内存空间内,给数组开辟内存空间的行为由 new 关键字相关的操作完成; 数组变量可以使用null来赋值;
拓展: null表示空引用的字面量, 变量为null时表示该引用类型变量没有引用任何对象
数组的定义
定义格式两种
数据类型[] 数组名;
数据类型 数组名[];
最佳实践: 使用 数据类型[] 数组名 方式定义数组最直观,如 int[] nums; 可以明了地看出nums是int类型的数组
数组初始化
!!! 警告: 数组必须初始化后才能使用,否则会出现空引用异常
Java的数组是不可变的,初始化数组后数组的长度就不会再改变了,固定下来;只能通过重新初始化另一个数组
数组静态初始化
通过定义数组后立即设置初始值的方式会再去使用该数组
初始化格式如下
数组名 = new 数据类型[]{元素1, 元素2, 元素3...};
数组名 = {元素1, 元素2, 元素3...} // 简写格式,存在局限:只能在定义紧接时初始时使用这个语句
关键点
· 静态初始化的数组根据分配的元素内容来自动确定数组的长度
· 使用这种方式初始化数组必须要有具体数组的元素
数组的内存分析
创建数组时,表示数组的变量存在于栈的当前方法栈帧之中,而内部所存的值是堆内存的地址值,而该地址值指向的是实际在堆中内存里的数组数据,而这个内存空间由数组的new操作开辟的
拓展: 引用变量 - 对于引用对象的变量来说,变量内部存的对象的堆地址,操作引用变量的底层就是操作堆中的引用对象
数组动态初始化
· What: 直接初始化指定数组长度,而不手动设置数组元素的值时的操作
· Where: 当清楚数组长度,但不明确数组元素的具体内容采用这种初始化方法
动态初始化的特点就是 先限定长度, 再赋真正初始值;
首先根据限定的长度,然后系统会自动为数组的元素提供默认初始值,其初始化格式如下
数组名 = new [数组长度];
针对每种类型都要特定的默认值,具体如下
!!! 警告: 初始化数组时不能将静态初始化和动态初始化一起使用,即不能再表明数组个数的同时指定元素的值
数组的操作
访问数组元素采用固定格式
数组元素类型 变量名 = 数组名[索引号]
给数组元素赋值的固定格式
数组名[索引号] = 同类型数据
索引为0~length-1,如果用索引范围之外的数字作为下标访问数组时会出现(ArrayIndexOutOfBoundsException)数组索引越界异常,需要警惕!!!
遍历数组的操作,尤其是明确数组个数的情况下,使用for循环语句进行数组元素和索引的遍历,注意这种方式的遍历属于线性操作,性能不高
Java5的数组加强
Java5对数组常用的操作进行了编译优化,提供多种语法糖,以此提高开发者开发效率
增强for循环(for-each)
for-each采用忽略索引号,直接获取元素的方式遍历数组,格式如下
for(元素数据类型 变量名 : 数组名)
{
// 元素相关的操作
}
for-each中的””不能省略
for-each循环限制了无法直接操作数组中基本数据的值,只能操作数组的引用对象
where: 当需要迭代某数组元素,不关心索引号时使用
VIP: 通过反编译,底层编译器就for-each格式的语法转化为普通for循环遍历数组元素的方式
数组与方法的可变参数
为了让方法可以接受的参数不再是固定的个数,而是根据实际传入的情况去处理,采用可变参数来实现,格式如下
方法名(参数类型...参数名) {
}
可变参数的表现形式就是 参数个数可变;而底层本质仍是数组,当调用可变方法时,编译器会自动为可变参数创建一个数组,让方法体在数组的方式访问里面的参数
关键点
· 只能出现一个可变参数, 并且只能放置在最后,否则容易造成方法参数歧义
· 对于可变参数的方法,在不传值的情况下默认创建空数组即{},访问时不会出现空引用异常
二维数组
What: 当某个数组中的元素也是一个普通的数组 即数组中的数组
· 动态分配数组时不允许高维没有分配内存空间而直接给低维分配空间
· 遍历多维数组的常见方式就是使用for循环嵌套,来最终获取到最底层数组的元素值
(N维数组使用N次循环嵌套)
数组的算法相关
冒泡排序
冒泡的特征: 相邻两个比较,每一轮比较后忽略末尾元素
对于N个数的比较,先进行第一轮的N-1次比较,从第一次开始,比较结束后忽略末尾元素,进去下一轮,重复N-2次比较..直至最后只有两个数进行比较结束
冒泡排序的时间复杂度为O(N^2),效率较低
选择排序
选择排序的特征: 每轮比较获得最小元素的索引值,交换至最左端
对于N个数的比较,先进行第一轮的N-1次比较,假定最小索引min为0号,用min对应的元素与其他所有元素比较,当出现更小的元素时,把min索引改为更小的元素的索引,直至全部比较完后将最小索引的元素交换到最左,忽略最左的元素进去下一轮重复
选择排序的时间复杂度为O(N^2),效率较低
快速排序
特征
// TODO
快速排序的时间复杂度为O(Nlog(N)),效率高
二分查找
二分特征: 必须有序集合, 折半操作
针对一个有序的数组,先进行折半比较中间值,
若比中间值大则将低位下标移到中间索引后一位,
反之,将高位移到中间索引的前一位,如此重复下去
直到中间索引对应的元素等于要查找的元素
拓展 二分查找的时间复杂度为O(logN),效率较高
Java内置数组方法
注意: 访问Java内置数组方法时需要额外引入java.util包,也可以通过 java.util.Arrays.方法名(参数) 的方式访问
// 常用内置Arrays工具方法,每个方法都有多个类型的重载实现
static int binarySearch(byte[] a, int fromIndex, int toIndex, byte key);
static int[] copyOf(int[] original, int newLength);
static void sort(int[] a);
static String toString(float[] a);
系统工具类中很多方法用native修饰,表示方法底层调用的是用C/C++实现的方法