一、数组的定义和使用
1、概念:数组就是同一种类型数据的集合。数组其实就是一个容器。
2、数组的好处:可以自动给数组中的元素从0开始编号,方便操作这些元素。
3、数组定义的格式:
【格式一】:元素类型[]数组名 = new元素类型[元素个数或者数组长度];
示例:
int[] arr = new int[3];
【格式二】:元素类型[]数组名 = new元素类型[]{元素,元素,……};
示例:
int[] arr = new int[]{1,2,3,4,5};
【格式三 ---静态初始化】:元素类型[]数组名 = {元素,元素,......};
示例:
int[] arr = {1,2,3,4,5};
a. 元素类型:指的是声明数组元素的数据类型。
b. 数组名:是用来标识这组相同数据类型的元素的名称,命名规则和变量相同。
c. 数组长度:表示声明的数组里面可以存放元素的个数。
d. new:使编译器根据数组长度在堆内存中开辟一块内存空间供该数组使用。
注意:
①.Java中数组的使用必须经过声明和分配内存空间两个步骤。
②.数组使用引用数据类型。引用数据类型其默认值是null,表示暂时还没有任何指向的堆内存空间。
③.Java中数组的初始化分为“动态初始化”和“静态初始化”。
动态初始化:先声明数组,然后再为数组中的每个元素赋值。
静态初始化:数组声明的同时就给每个元素赋值。
4、数组内存结构
5、Java的内存结构
栈内存:用于存储局部变量,当数据使用完,所占空间会自动释放。
堆内存:
- 数组和对象,通过new建立的实例都存放在堆内存中。
- 每一个实体都有内存地址值
- 实体中的变量都有默认初始化值
- 实体不在被使用,会在不确定的时间内被垃圾回收器回收
方法区、本地方法区、寄存器
注:在栈内存中保存的永远是数组的名称,只开辟了栈内存空间的数组是永远无法使用的,必须有指向的堆内存才可以使用,要想开辟新的堆内存则必须使用关键字new,然后只是将此堆内存空间的使用权交给了对应的栈内存空间。一个堆内存空间可以同时被多个栈内存空间所指向。
6、数组操作常见问题
①.数组脚标越界异常(ArrayIndexOutOfBoundsException)
int[] arr = new int[2];
System.out.println(arr[3]);
访问到了数组中的不存在的角标时发生。
②.空指针异常(NullPointerException)
int[] arr = null;
System.out.println(arr[0]);
arr引用没有指向实体,却在操作实体中的元素时。
③.示例:
int[] arr= {2,4,6,8,10,12};
System.out.println(arr); //输出结果:[I@60e128
“[I@60e128”表示打印了arr这个数组实体的引用。其中“[”表示这是一个一维数组,“I”表示这时一个int类型的数组,而“@”右边的部分表示的是该数组的在内存中的地址(是用hash算法算出来的hash值,用16进制表示)。
数组知识点:
①.要访问数组中的元素,可以利用角标索引来完成。Java中数组索引编号由0开始。
②.在Java中获取数组长度可以通过“数组名.length”的方式。
二、数组中的常见操作
1、获取数组中的元素:通常会用到遍历(一般会用到for循环)。
示例:
int[] arr = {2,4,6,8,10,12};
System.out.println("数组长度="+arr.length);
for (int x=0; x<arr.length ; x++ )
{
System.out.println("arr["+x+"]="+arr[x]+";");
}
2、获取最值(最大值、最小值)。
/*
获取数组中的最大值。
思路:
1、获取最值需要进行比较。每一次比较都会有一个较大的值。因为该值不确定,通过一个变量进行临时存储。
2、让数组中的每一个元素都和这个变量中的值进行比较。如果大于了变量中的值,就用该变量记录较大的值。
3、当所有的元素都比较完成,那么该变量中存储的就是数组中的最大值。
步骤:
1、定义一个变量。初始化为数组中的任意一个元素即可。
2、通过循环语句对数组进行遍历。
3、在遍历过程中定义判断条件,如果遍历到的元素比变量中的元素大,赋值给改变量。
需要定义一个功能来完成,以便提高复用性。
1、明确结果,数组中的元素 int类型。
2、位置内容:一个数组。int[]。
*/
public static int getMax(int[] arr)
{
int max = arr[0];
for(int x=1; x<arr.length; x++)
{
if(arr[x]>max)
max= arr[x];
}
return max;
}
/*
获取最大值的另一种形式。
可不可以将临时变量初始化为0呢?
可以。这种方式,其实是在初始化为数组中的任意一个角标。
*/
public static int getMax_2(int[] arr)
{
int max = 0;
for(int x=1; x<arr.length; x++)
{
if(arr[x]>arr[max])
max= x;
}
return arr[max];
}
/*
获取最小值。
*/
public static int getMin(int[] arr)
{
int min = arr[0];
for(int x=1; x<arr.length; x++)
{
if(arr[x]<min)
min = arr[x];
}
return min;
}
3、排序(选择排序、冒泡排序)
/*
选择排序:将数组中的每一个元素分别和它后面的元素进行比较,如果符合判断条件就进行换位。
内循环结束一次,最值出现在头角标位置上。
*/
public static void selectSort(int[] arr)
{
for(int x=0; x<arr.length-1; x++)
{
for(int y=x+1; y<arr.length; y++)
{
if(arr[x]>arr[y])
{
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
/*
冒泡排序:相邻的两个元素进行比较,如果符合条件就换位。
第一圈:最值出现在最后位。
*/
public static void bubbleSort(int[] arr)
{
for(int x=0; x<arr.length-1; x++)
{
for(int y=0; y<arr.length-x-1; y++) //-x:让每一次比较的元素减少。-1:避免角标越界。
{
if(arr[y]>arr[y+1])
{
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
/*
折半查找。提高效率,但是必须要保证该数组是有序的数组。
*/
public static int halfSearch(int[] arr,int key)
{
int min,max,mid;
min = 0;
max = arr.length-1;
mid = (max+min)/2;
while(arr[mid]!=key)
{
if(key>arr[mid])
min = mid + 1;
else if(key<arr[mid])
max = mid - 1;
if(min>max)
return -1;
mid = (max + min) / 2;
}
return mid;
}
/*
折半的第二种方式。
*/
public static int halfSearch_2(int[] arr,int key)
{
int min = 0,max = arr.length-1,mid;
while(min<=max)
{
mid = (max+min)>>1;
if(key>arr[mid])
min = mid + 1;
else if(key<arr[mid])
max = mid - 1;
else
return mid;
}
return -1;
}
三、二维数组
1、二维数组:数组中的数组。(如果一维数组是数学几何中的线性图形,那么二维数组相当于是一个类似Excel表格一样的表格)
2、二维数组的声明格式:
元素类型[][]数组名 = new元素类型[二维数组的长度][一维数组的长度];
元素类型[][]数组名 = {{元素,元素,...},{元素,元素,...},{元素,元素,...},...};
示例1:
int[][] arr =new int[3][2];
- 定义了名称为arr的二维数组
- 该二维数组中有3个一维数组
- 每一个一维数组中有2个元素
- 一维数组的名称分别为arr[0], arr[1], arr[2]
- 给第一个一维数组1角标位赋值为78写法是:arr[0][1] = 78;
示例2:
int[][] arr =new int[3][];
- 二维数组中有3个一维数组
- 每个一维数组都是默认初始化值null
- 可以对这个三个一维数组分别进行初始化
arr[0] = newint[3];
arr[1] = new int[1];
arr[2] = new int[2];
示例3:
int[][] arr ={{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;
注意:一维数组如果要全部输出,需要使用一层循环;二维数组全部输出需要二层循环......以此类推,N维数组,则需要N层循环。
四、个人总结:
1、数组是一组相同类型的数据的集合。数组按存放元素的复杂程度可以分为一维数组、二维数组...多维数组。
2、Java中的数组使用必须要经过声明和开辟堆内存空间两个步骤。声明数组是在栈内存中开辟空间,可以通过new关键字开辟堆内存空间供数组使用。
3、Java中获取数组的长度可以利用“数组名称.length”这个属性来完成。
4、可以通过角标的方式访问数组中的元素。如果超过了角标的范围,就会出现“角标越界”的异常。
5、数组属于引用数据类型。对数组的引用实际上就是堆内存地址的传递。
6、数组中,多个栈内存空间可以同时指向同一个堆内存地址。