第一章 数组的定义和范围
1.1、产生背景:
在通常的统计或者分析过程中,我们需要定义同种类型的多个变量,重复的定义过于麻烦,所以我们需要一个容器将一连串同种类型的数据装进去,调用时只需要调用一种容器即可,而这种容器即为数组。
1.2、概念:
数组就是存储数据长度固定的容器,保证多个数据的数据类型要一致。
1.3、特点:
(1)、数组是一种引用数据类型。
(2)、数组当中的多个数据,类型必须统一。
(3)、数组的长度在程序运行期间不可改变。
1.4、定义格式:
(1)、动态初始化(指定长度)
数组储存的数据类型[] 数组名字 = new 数组储存的数据类型[长度];
(2)、静态初始化(指定内容)
//标准格式 数据类型[] 数组名称 = new 数据类型[] { 元素1, 元素2, ... }; //省略格式 数据类型[] 数组名称 = { 元素1, 元素2, ... };
名词或符号的释义:
(1)数组储存的数据类型:创建的数组容器可以存储什么数据类型。(所有元素统一)
(2)[ ] :表示数组。
(3)数组名字:为定义的数组起个变量名,满足标识符规范,可以使用名字操作数组。
(4)new :关键字,创建数组使用的关键字。
(5)长度:数组的长度,表示数据容器中可以存储多少个元素。
使用建议:如果不确定数组当中的具体内容,用动态初始化;已经确定了具体内容,用静态初始化。
注意事项:(1)静态初始化没有直接告诉数组的长度,可以根据元素的个数推断出数组长度。
(2)动态初始化数组有定长特性,长度一旦指定,不可更改。
实例:
public class TestArray{ public static void main(String[] args) { // 省略格式的静态初始化 int[] arrayA = { 10, 20, 30 }; // 静态初始化的标准格式. int[] arrayB= new int[] { 11, 21, 31 }; // 动态初始化的标准格式 int[] arrayC= new int[5]; // 注意事项:静态初始化和动态初始化的标准格式可以拆分成两个步骤 // 静态初始化的省略格式,不能拆分成为两个步骤。 } }
1.5、数组的访问
(1)索引:每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,到(length-1)结束,这个自动编号称为数组索引(index),可以通过数组的索引访问到数组中的元素。
(2)访问格式:
数组名[索引]
(3)数组的长度:每个数组都具有长度,采用语句:数组名.length 可以得到数组的长度,得到的数组长度必然是一个int类型数值。
实例:
public class BlogTest { public static void main(String[] args) { int [] arr = {10,20,30}; //打印数组的长度,输出结果为3 System.out.println(arr.length); } }
(4)动态初始化数组时,元素被自动赋予默认值的规则:
整数类型,默认为0 浮点类型,默认为0.0
字符类型,默认为‘u000’ 布尔类型,默认为false
引用类型,默认为null
注意事项:
(1)索引值从0开始,一直到"数组长度-1"结束。
(2)直接打印数组的名称,直接得到的是数组的内存地址哈希值。
(3)静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成具体数值。
实例:
public class BlogTest { public static void main(String[] args) { //静态初始化一个数组 int [] arr ={10,20,30,40,60}; //动态初始化创建一个数组 int [] arr1 = new int[8]; //从静态数组中利用索引值打印数据 System.out.println(arr[0]); //得到两种数组的地址哈希值 System.out.println(arr); System.out.println(arr1); //从动态数组中利用索引值打印默认数据 System.out.println(arr1[0]); } }
运行结果:
第二章 数组原理内存图
2.1 内存概述
内存是计算机中的重要原件,临时存储区域,作用是运行程序。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。
Java虚拟机需要运行程序,必须要对内存进行空间的分配和管理。
2.2 Java虚拟机的内存划分
(1)方法栈(stack):存放的都是方法中的局部变量。方法的运行一定要在栈当中运行。
拓展:局部变量:方法的参数,或者是方法语句体中的变量。
作用域:一旦超出作用域,立刻从栈内存当中消失。
(2)堆内存(Heap):存储对象或者数组,凡是new创建的对象或者数组,都在堆中。
拓展:堆内存里面的东西都有一个地址值:16进制
堆内存里面的数据,都有默认值,规则和数组动态初始化默认值的规则相同。
(3)方法区(Area):存储.class相关信息,包含方法的信息。
(4)本地方法栈(Native Method Stack):与操作系统相关。
(5)寄存器(pc Register):与CPU相关。
2.3 数组在内存中的存储
(1)一个数组内存图
源程序
public class Demo01ArrayOne { public static void main(String[] args) { int[] array = new int[3]; // 动态初始化 System.out.println(array); // 地址值 System.out.println(array[0]); // 0 System.out.println(array[1]); // 0 System.out.println(array[2]); // 0 System.out.println("=============="); // 改变数组当中元素的内容 array[1] = 10; array[2] = 20; System.out.println(array); // 地址值 System.out.println(array[0]); // 0 System.out.println(array[1]); // 10 System.out.println(array[2]); // 20 } }
内存中的体现
解释:(1)首先.class程序入口进入方法曲(public static void main(String [ ] args))
(2)main方法优先进入方法方法栈中执行
(3)在main中创建新数组(new),JVM会在堆内存中开辟空间,存储数组
(4)数组在堆内存当中得到了自己的内存地址,以十六进制数表示。
(5)数组中的三个元素在没有赋值之前默认值均为0
(6)JVM将数组的内存地址赋给引用类型变量arr(new的那部分还在堆内存中)
(7)无论是在调用arr进行元素赋值还是更改原来元素值时,都是利用arr中储存的地址值去堆内存中找到数组并对元素值进行修改。
(2)两个数组内存图
源程序
public class Demo02ArrayTwo { public static void main(String[] args) { int[] arrayA = new int[3]; System.out.println(arrayA); // 地址值 System.out.println(arrayA[0]); // 0 System.out.println(arrayA[1]); // 0 System.out.println(arrayA[2]); // 0 System.out.println("=============="); arrayA[1] = 10; arrayA[2] = 20; System.out.println(arrayA); // 地址值 System.out.println(arrayA[0]); // 0 System.out.println(arrayA[1]); // 10 System.out.println(arrayA[2]); // 20 System.out.println("=============="); int[] arrayB = new int[3]; System.out.println(arrayB); // 地址值 System.out.println(arrayB[0]); // 0 System.out.println(arrayB[1]); // 0 System.out.println(arrayB[2]); // 0 System.out.println("=============="); arrayB[1] = 100; arrayB[2] = 200; System.out.println(arrayB); // 地址值 System.out.println(arrayB[0]); // 0 System.out.println(arrayB[1]); // 100 System.out.println(arrayB[2]); // 200 } }
内存中的体现
解释:分开采用一个数组的内存图组合而成,两者并没有联系。
(3)两个引用指向同一个数组的内存图
源程序
public class Demo03ArraySame { public static void main(String[] args) { int[] arrayA = new int[3]; System.out.println(arrayA); // 地址值 System.out.println(arrayA[0]); // 0 System.out.println(arrayA[1]); // 0 System.out.println(arrayA[2]); // 0 System.out.println("=============="); arrayA[1] = 10; arrayA[2] = 20; System.out.println(arrayA); // 地址值 System.out.println(arrayA[0]); // 0 System.out.println(arrayA[1]); // 10 System.out.println(arrayA[2]); // 20 System.out.println("=============="); // 将arrayA数组的地址值,赋值给arrayB数组 int[] arrayB = arrayA; System.out.println(arrayB); // 地址值 System.out.println(arrayB[0]); // 0 System.out.println(arrayB[1]); // 10 System.out.println(arrayB[2]); // 20 System.out.println("=============="); arrayB[1] = 100; arrayB[2] = 200; System.out.println(arrayB); // 地址值 System.out.println(arrayB[0]); // 0 System.out.println(arrayB[1]); // 100 System.out.println(arrayB[2]); // 200 } }
在内存中的表现
解释:把第一个数组的名称直接赋给第二个数组,实际上是将第一个数组的地址赋予了第二个数组。第二个数组与第一个数组的地址相同,在堆内存中使用相同数组 。第二个数组通过第一个数组的地址对 第一个数组内元素的数值进行修改。
第三章 数组的常见操作
3.1 数组越界异常
(1)规范:数组的索引编号从0开始,一直到"数组的长度-1"为止
(2)异常:访问数组是所采用的索引编号不存在,就会发生数组所以越界异常
实例:
public class BlogTest { public static void main(String[] args) { //静态初始化一个数组 int [] arr ={10,20,30,40,60}; //访问数组中不存在的元素 System.out.println(arr[8]); } }
运行结果:
3.2 数组空指针异常
(1)了解:所有的引用类型变量,都可以赋值为一个null值,但是代表其中什么都没有。
(2)数组规范:数组必须进行new的初始化才能使用其中的元素。
如果数组仅仅只被赋值了一个null,没有进行new创建,那么就会产生空指针异常。
实例:
public class BlogTest { public static void main(String[] args) { //静态初始化一个数组 int [] arr ={10,20,30,40,60}; //访问被赋值为null的数组中的元素,不经过new的创建。 int [] arr1 = null; System.out.println(arr[1]); System.out.println(arr1[1]); } }
运行结果:
3.3 数组的遍历
(1)定义:就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。
(2)方法:利用for循环语句循环打印出数组中的每一个元素。
实例:
public static void main(String[] args) { int[] arr = { 1, 2, 3, 4, 5 }; for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } }
运行结果:
3.4 获取数组中的最大元素
(1)实现思路:定义变量(存储第0号元素)—遍历数组—将其它元素与定义的变量进行比较,较大者替换较小者。
实例:
public class BlogTest { public static void main(String[] args) { int[] arr = { 105, 34, 85, 1111, 164, 542 }; //定义变量,保存数组中0索引的元素 int max = arr[0]; //遍历数组,取出每个元素 for (int i = 1; i < arr.length; i++) { //遍历到的元素和变量max比较 //如果数组元素大于max if (arr[i] > max) { //max记录住大值 max = arr[i]; } } System.out.println("数组最大值是: " + max); } }
运行结果:
3.5 数组的反转
(1)定义:数组中的元素颠倒顺序,例如原始数组为1,2,3,4,5,反转后的数组为5,4,3,2,1
(2)实现思路:将数组两端的元素交换—需要两个变量来储存最大索引和最小索引—将两个索引的元素进行交换—最大索引递减,最小索引递增,重复操作—最小索引超过最大索引,反转结束。
实例:
public class BlogTest { public static void main(String[] args) { int[] array = { 15, 25, 35, 45, 55 }; // 遍历打印数组本来的样子 System.out.print("反转前:"); for (int i = 0; i < array.length; i++) { System.out.print(array[i]+" "); } //数组反转 for (int min = 0, max = array.length - 1; min < max; min++, max--) { int temp = array[min]; array[min] = array[max]; array[max] = temp; } // 再次打印遍历输出数组后来的样子 System.out.print("反转后:"); for (int i = 0; i < array.length; i++) { System.out.print(array[i]+" "); } } }
运行结果:
第四章 数组作为方法参数或返回值
4.1 数组作为方法参数
(1)注意事项:当调用方法的时候,向方法的小括号进行传参,传递进去的其实是数组的地址值。
实例:
public class BlogTest { public static void main(String[] args) { int[] array = { 15, 25, 35, 45, 55 }; System.out.println(array); // 地址值 printArray(array); // 传递进去的就是array当中保存的地址值 } //创建打印数组的方法printArray public static void printArray(int[] array) { //利用数组作为参数 System.out.println("printArray方法收到的参数是:"); System.out.println(array); // 地址值 for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } } }
运行结果:
4.2 数组作为方法返回值
(1)了解:任何数据类型都能作为方法的参数类型,或者返回值类型。
(2)数组作为方法返回值的背景:如果希望一个方法返回多个结果数据,则需使用一个数组作为返回值类型。
(3)注意事项:(1)数组作为返回值,返回值类型则对应数组的引用类型。
(2)数组作为方法的返回值,返回的也是数组的地址值。
实例:
public class BlogTest { public static void main(String[] args) { //在main方法中创建一个数组接收calculate方法返回的数组 int[] result = calculate(10, 20, 30); System.out.println("main方法接收到的返回值数组是:"); System.out.println(result); // 地址值 System.out.println("总和:" + result[0]); System.out.println("平均数:" + result[1]); } public static int[] calculate(int a, int b, int c) { int sum = a + b + c; // 求和 int avg = sum / 3; // 求平均数 int[] array = {sum, avg}; System.out.println("calculate方法内部数组是:"); System.out.println(array); // 地址值 return array;//地址值 } }
运行结果: