1.数组的定义、声明和创建

  定义:数组是相同类型数据的有序集合,其中每一个数据称为数组元素,我们通过数组的下标(即序号)去访问每个元素。注意:在Java中,数组元素下标是从0开始的。

  声明:有两种方法。

  1)datatype[] arrayRefVar; //首选方法;

  2)datatype arrayRefVar[]; //和上一个方法效果相同,但这里是c++、c语言的代码习惯。

  创建:在声明后需要用new操作符来创建一个数组。

  datatype[] arrayRefVar = new dataType[arraySize]; 

  创建之后再对数组元素进行初始化,如果没有初始化那么元素就均为默认值(比如int类型为0,string类型为null等)。

  数组长度获取:arrays.length

 

2.数组的初始化和内存分析

  Java内存一般分为三个部分:

  1)堆:主要用于存放new的对象和数组,可以被所有的线程共享,不会存放别的对象引用;

  2)栈:存放基本变量类型(包括这个基本类型的具体数值),也存放引用对象的变量(会存放这个引用在堆里面的具体地址);

  3)方法区:包含了所有的class和static变量,可以被所有的线程共享。

  在声明并创建数组的整个过程里,Java的内存分配:

  

java 数组下标不溢出 java数组的下标的数据类型_初始化

  

java 数组下标不溢出 java数组的下标的数据类型_数组_02

  

java 数组下标不溢出 java数组的下标的数据类型_数组_03

  数组的三种初始化类型

  1)静态初始化;

  int[] a = {1, 2, 3, 4, 5}; //直接创建数组并赋值

  Man[] mans = {new Man(), new Man2()}; //引用类型数组

  2)动态初始化;

  int[] nums; //声明一个数组

  nums = new int[5]; //创建一个数组

  nums[0] = 1; //给数组赋值

  或者也可以 int[] nums = new int[5]; //直接声明并创建数组

  3)默认初始化。

  数组是引用类型,其元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也如实例变量一般被隐式初始化(0/0.0/null)。一般动态初始化就伴有默认初始化的过程。

  

  数组的特点

  1)Java中数组长度为定值,数组一旦被创建,数组长度就不能改变;

  2)数组元素类型可以是任何数据类型,包括基本数据类型或者引用类型,但必须是相同类型,不能出现混合类型;

  3)数组变量属于引用类型,数组可以看成为对象,其中每个元素可以看做对象的成员变量。数组本身是作为对象保存在JVM的堆中,因此数组不论是保存原始类型还是引用类型,其本身是在堆中的。

  数组下标越界:数组的下标范围为[0, array.length-1],当输入的数组下标超出了数组长度,此时内存读取越界,java会报报java.lang.ArrayIndexOutOfBoundsException错误。

  多维数组:可以看做是数组的数组,例如int[][] arrays = {{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}}; //这里数组可以看做是5行2列的矩阵,[5][2]

 

3.Arrays类

  Java中的工具类:java.util.Arrays,主要是用于对数组中的数据对象进行一些基本操作,具体方法参考https://docs.oracle.com/javase/8/docs/api/的API帮助文档。这个工具类中的所有方法都是static类型的,所以我们是直接使用类名进行调用,而不能使用对象来进行调用。下面是一些常用的功能:

  1)fill方法:将数组中部分或全部元素替换成你提供的某个值,Arrays.fill(int[] a, int value) 或 Arrays.fill(int[] a, int fromIndex i, int toIndex J, int value) //第二个为部分替换;

  2)sort方法:将数组中元素按升序排列;

  3)equals方法:比较数组中元素是否相等;

  4)binarySearch方法:对排列好的数组进行二分查找法操作。

  我们不需要过分依赖Java中已有的工具类,根据要实现的功能特点,很多时候我们也可以自己编写相关算法以更好地实现我们的目的,工具类主要为了避免重复造轮子的低效场景。

 

4.冒泡排序

  冒泡排序是笔试或面试中常考的排序算法之一(常见的排序算法有8种)。

  基本思路:两层循环,外层为冒泡轮数(一般循环次数为数组长度-1),内层依次对数组中相邻的两个数进行比较,如果第一个数大于第二个,则将二者换位(升序冒泡),内层的循环次数一般为数组长度-1-外层当前冒泡轮数。具体细节见下图示例代码。

  整体的时间复杂度为O(n^2)。

  算法示例:

java 数组下标不溢出 java数组的下标的数据类型_初始化_04

  代码示例:

java 数组下标不溢出 java数组的下标的数据类型_初始化_05

 

java 数组下标不溢出 java数组的下标的数据类型_初始化_06

 结果:

java 数组下标不溢出 java数组的下标的数据类型_Java_07

 

5.稀疏数组

   稀疏数组是一种数据结构,主要用于数组(矩阵)压缩。当一个数组大部分元素为同一值(比如0)时,此时包含较多的无效值,我们可以通过稀疏数组来保存这个数组,这样保存只需要较小的存储空间,从而实现了压缩的效果。

  具体算法原理:

  1)记录数组的行列数,以及其中的有效数数量;

  2)记录有效值及其行列坐标;

  3)将上述数据保存在列数为3的稀疏矩阵中,第一行分别存储行列数及有效数数量,之后的每一行分别存储有效值的行列坐标及对应数值。

  示例:

  原数组:

  

java 数组下标不溢出 java数组的下标的数据类型_java 数组下标不溢出_08

  稀疏数组:

  

java 数组下标不溢出 java数组的下标的数据类型_数组_09

  算法代码示例:

  

java 数组下标不溢出 java数组的下标的数据类型_初始化_10

  

java 数组下标不溢出 java数组的下标的数据类型_Java_11

  结果:

  

java 数组下标不溢出 java数组的下标的数据类型_数组_12