目录
7、Array 类的使用
1、数组的定义
1.1数组的概念
数组:数组表示的一串连续的存储空间。每个空间中都可以保存一个数据。当我们需要操作的时候,不要去面对单个空间,而直接面对这个整体的连续的存储区域。
1.2数组的定义方式
1.2 .1 数组的静态初始化(第一种定义格式)
静态初始化:初始化数组与给数组元素赋值同时进行。
即在定义数组的时候,如果已经知道数组中的具体数据,这时可以在定义数组的时候直接书写具体的数据。
格式:
数据类型[] 数组名 = {值,值,值.......};
int[] arr={11,22,33,44,-1,0};
1.2.2 数组的动态初始化(第二种定义格式)
动态初始化:初始化数组与给数组元素赋值分开进行
格式:
数组中保存的数据类型[] 数组的名 = new 数组中保存的数据类型[ 开辟的连续空间个数 ];
把上述定义的格式可以翻译成下述格式:
数据类型[] 数组名 = new 数据类型[长度] ;
//定义变量:
数据类型 变量名 = 值;
int a = 123;
//定义数组:
int[] arr = new int[4];
在内存中一次开辟4个连续的空间,每个空间都是int类型,
并且这些空间中保存的数据也必须是int类型。
1.3 数组的遍历
需求:将数组中每一个数据打印到屏幕上。
数组的遍历:
- 遍历:把数组的所有空间都访问一遍。
- 访问数组的空间需要使用:数组名+数组的下标,才能访问到数组的每个空间。
- 同一个数组,名称是统一的,只有下标。而下标是从零开始,到长度-1结束,
- 下标是在有序的增加。
public class Demo4 {
public static void main(String[] args) {
int[] arr = new int[]{111, 222, 333};
for (int i = 0; i < arr.length ; i++ ) {
System.out.println(arr[i]);
}
}
}
1.4 数组的默认初始化值
因为数组的创建都是通过new出来的,new是一个关键字,已经有点面向对象的意思了;
所以需要注意的是,数组是引用类型的,那么它和之前讲的基本类型之间是有区别的;
如果是引用类型变量,只要一旦创建(new),那么jvm虚拟机会自动给它先赋一个默认的初始化值:例如:
Int[] arr = new int[5];
说明在内存中开辟一组空间,一共有5块区域,虽然是动态初始化,没有赋具体的值但是有默认的初值为:0
- int[0]~int[5]的五块区域的值都为0
- double[]、float[]默认的初始化值为:0.0
- byte[]、short[]、long[]默认的初始化值为:0
- char[]默认的初始化值为:’\u0000’
- boolean[]默认的初始化值为:false
1.5 数组的弊端
- 数组一旦初始化,它的长度是不可变的;
- 集合可以解决数组这个弊端
public class Demo4 {
public static void main(String[] args) {
int[] i = new int[]{12,13,14};
int[] j = new int[10];
for (int k = 0; k < i.length ; k++ ) {
j[k] = i[k];
}
//数组i的长度为3,数组j只能得到三个数据,对应下标0,1,2的空间
j[3] = 15;
j[4] = 16;
}
}
2、数组内存图解
2.1 Java 的内存分配
JVM把内存划分成5片区域:
①栈内存:栈内存主要是用来运行函数的,在函数中定义的所有变量,都会在这个内存开辟空间。
在栈内存中定义的变量,不初始化,是不能直接使用的。
注意:所有的函数都必须在栈内存中运行。
而jvm只会运行处于栈内存顶部的函数。
函数被加载到栈内存的动作,称为函数的压栈(入栈)。
函数执行完之后就会从栈中消失(函数的弹栈,或者叫做出栈)
②堆内存:在程序中使用new 关键字创建出来的所有东西,都会保存在堆内存中。
堆内存中开辟的空间,不赋值,都会有默认的初始化数据。
整数:默认是0
小数 默认是0.0.
boolean 默认是false
char 默认是 空格
③方法区:
JVM在加载class文件的时候,所有的class文件就要加载在这个内存中。(先了解,后面会详细讲解)
④本地方法区:主要是保存native关键字标注的方法
⑤寄存器:是给CPU使用的
2.2 数组的内存分配
数组的简单操作:
我们需要通过数组的总名称 引用变量空间,然后通过这个引用空间中的地址,再去找到堆内存中的连续的空间,然后才能准确的去操作数组。
获得数组中每个空间中的值:
数组名[下标];
给数组的每个空间赋值:
数组名[ 下标 ] = 值;
我们定义的数组名空间:
它是一个特殊的内存空间,它中只能保存某个数字在堆中的内存地址。而不能像前面学习普通变量一样来保存普通的常量。
数组名空间保存某个数组的地址,而数组的每个真实空间保存具体的普通常量数据。
3、数组的常见的问题
3.1 数组角标越界异常
3.2 空指针异常
图解说明:
注意,在 java 中当被 new 出来的堆中的内存,没有任何一个引用指向它的时候,这时它就是一个垃圾,JVM 就使用垃圾回收器把当前这片内存清理。
//例:请问堆中有垃圾嘛?
int[] arr = new int[5];
int[] arr2 = arr;
arr = null;
答案:没有,因为上述代码,先有2个引用变量指向数组,后面虽然把一个引用赋值null,但还有一个引用指向数组,这时是没有垃圾的。如果一个内存空间没有任何引用指向,这时这片内存才会变成垃圾。
4、数组的应用
4.1 遍历
/**
* 例:
* 1、随便定义一个数组,对其遍历。
* 2、由于数组的下标是有序增加的,所以可以使用循环提供数组的下标
* 3、在屏幕上将数组中的数据打印出来,并且每个数据之间用逗号隔开。
*/
public class ArrayDemo05 {
public static void main(String[] args) {
Demo01();
System.out.println("====================");
Demo02();
}
//方式一:直接打印
public static void Demo01() {
//定义数组
int[] arr = {1, 2, 12, 4, 5, 6, -1, 0};
//遍历数组,将数组中的元素打印到控制台
for (int i = 0; i < arr.length; i++) {
System.out.println("arr[" + i + "] =" + arr[i]);
}
}
/**
* 方式二:将打印语句封装到函数中
*/
public static void Demo02() {
//定义数组
int[] arr = {1, 2, 12, 4, 5, 6, -1, 0};
//调用函数
printArray(arr);
}
/**
* 把打印数组的独立代码单独封装到一个函数中
* 在定义函数的时候时刻要思考函数需不需要返回值,
* 还要确定当前的函数需不需要接收参数
* @param arr
*/
public static void printArray(int[] arr) {
for (int i = 0; i <= arr.length - 1; i++) {
//如果数据是最后一位,就不需要打印逗号
if (i == arr.length) {
System.out.println("arr[" + i + "] =" + arr[i]);
} else {
System.out.println("arr[" + i + "] =" + arr[i] + ",");
}
}
}
}
4.2 求和
/**
* 例:计算数组中所有数据的和:
* 1.定义一个存储数据的数组;
* 2.定义一个变量用来接收数组中所有数据的和;
* 3.遍历数组,取出数组中的数据依次和上面的定义的变量相加;
* 4.将求和的功能封装成一个函数,将求和的结果返回给调用者并打印。
*/
public class ArrayDemo05 {
public static void main(String[] args) {
//定义数组
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//调用自定义的函数
Integer sum = SumArray(arr);
//在屏幕上打印数组中所有数据的和
System.out.println("sum = " + sum);
}
//求和的函数(接口)
public static Integer SumArray(int[] arr) {
//定义一个变量接收数组中所有数据的和
int sum = 0;
//遍历取出数组中每个空间中的数据
for (int i = 0; i < arr.length; i++) {
//将数组中的每个数据和变量sum相加
sum += arr[i];
}
//将数组的数据和sum返回给调用者
return sum;
}
}
4.3 数组求最值
数组的最值问题:
在对数组求最值的时候,一般我们会假设一个值为最大值或者最小值,然后遍历数组中的所有空间,和假设的这个值进行大小比较,只要从数组中取出的值比假设的值大 或者 小, 就进行替换。
最终把数组遍历完成,就能找到最大值 或者 最小值。
注意:一般要求假设的这个值一定是数组中存在的值。
/**
* 例:计算数组中的最大值或者最小值。
* 1.定义一个有数据的数组。
* 2.定义一个变量max用来接收数组中最大的数据。
* 3.假设数组中第一个空间中的数据最大,并将数组中的第一个空间的数据赋值给变量max。
* 4.使用for循环遍历数组中的数据,依次取出数组空间中的数据并和max进行比较。
* 5.如果取出的数据大于max中保存的数据,则将该数据保存到max空间中。
* 6.将上述求最值的功能代码封装到函数中,并将保存数组中最大数据的max返回给调用者。
*/
public class ArrayDemo06 {
public static void main(String[] args) {
//定义数组
int[] arr = {1, 3, 4, 5, 6};
//调用自定义函数
int max = getArrayMax(arr);
System.out.println("max = " + max);
}
public static int getArrayMax(int[] arr) {
//定义一个变量,存放最值
int max = arr[0];
//使用循环取出数组中空间的数据和假设的最大值进行比较
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
//比较结束后将最大值max返回给调用者
return max;
}
}
4.4 数组的使用思想
数组:称为一类容器。它中可以保存多个数据。
当我们有多个数据的时候,并且数据的类型是统一的,同时个数也是确定的,这时就可以使用数组保存。
数据少了使用变量保存,数据一旦多了,就使用数组保存。
5、数组的排序
排序:其实就是把一些没有顺序的数据,按照特定的规则进行排列。
排序的方式有两种:升序(从小到大) 降序(从大到小)
5.1 选择排序
选择排序,从数组空间中选择第一个空间然后和其它空间中的数据进行比较,如果要求升序排列,那么选择的这个空间中的数据和其它空间中的数据比较完之后将最小的数据和当前的第一个空间中的数据进行互换位置,然后再选择第二个空间中的数据和除第一个空间中的数据进行比较,同样找出最小的数据,将两个空间中的数据进行位置互换。后面的数据以此类推,一直将所有的数据变成从小变大的数据为止。
降序排序,方向相反。
/**
* 选择排序代码实现得思路和步骤:
* 1)定义一个数组。
* 2)定义一个函数将选择排序的功能封装到函数中。
* 3)如果两个空间中需要交换数据,这时需要定义一个临时变量temp来保存选中空间的数据。
* 4)使用for循环对选中空间的下标进行遍历,这个for循环作为外层循环。
* 5)使用for循环对选中空间后面的空间的下标进行遍历,这个for循环作为内层循环。
* 6)使用判断结构对选中空间中的数据和后面的空间中的数据进行比较,如果选中空间中数据大于后面空间中的数据,则交换空间中的数据。如果选中空间中数据小于后面空间中的数据,则不交换空间中的数据。
* 7)在定义一个函数用来打印数组中的数据。
*/
public class ArrayDemo08 {
public static void main(String[] args) {
int[] arr = {11, 22, 33, 44, 55, 66, 77, 99, 0, -1};
//打印数组
printArr(arr);
System.out.println("---------------");
//对数组进行升序
int[] acs = acsSort(arr);
printArr(arr);
System.out.println("---------------");
//对数组进行降序
int[] desc = descSort(arr);
printArr(arr);
}
//数组升序排序
public static int[] acsSort(int[] arr) {
//对数组进行升序
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length; j++) {
//数组进行对比
if (arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
//数组降序排序
public static int[] descSort(int[] arr){
//对数组进行降序排列
for (int i = 0; i < arr.length; i++) {
//数组进行对比
for (int j = 0; j < arr.length; j++) {
if (arr[i] < arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
//打印数组
public static void printArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println("arr[" + i + "] =" + arr[i]);
}
}
}
6、数组查找
数组查找:就是去遍历数组,找到数组中的某个元素,并找到该元素的位置。
6.1 一般查找
/**
* 例:从指定的数组中找出指定值的下标。
* 1、 定义一个数组
* 2、需要定义一个功能(函数),然后接收调用者传递进来的数组和指定的值key,需要返回找到的下标。
* 3、循环遍历数组,在遍历的过程中取出数组的中的值和指定的key进行比较:
* 相等就找到,返回当前的下标。
* 4、如果循环都结束了,也没有相等的,说明当前指定的数据,在数组中不存在,
* 一般只要是程序中关于查找的问题,没有找到统一都返回-1
*/
public class ArrayDemo07 {
public static void main(String[] args) {
//定义一个数组
int[] arr = {-2,11,22,33,44,55,66,77,99,0,-1};
int index = getIndex(arr,3);
System.out.println("index = " + index);
}
public static int getIndex(int[] arr, int key) {
/*
循环遍历数组,在遍历的过程中取出数组的中的值和指定的key进行比较
相等就找到,返回当前的下标,如果循环都结束了,也没有相等的,
说明当前指定的数据,在数组中不存在,
一般只要是程序中关于查找的问题,没有找到统一都返回-1
*/
for (int i = 0; i < arr.length; i++) {
if (key == arr[i]) {
return i;
}
}
//如果循环都结束了,说明根本就没有找到和指定的值相等的数据
return -1;
}
}