第一章 数组的定义和访问

1.1 数组的概念及特点

概念

  1. 是一种容器,可以同时存放多个数据值

特点

  1. 1,数组是一种引用数据类型
  2. 2,数组当中的多个数据,类型必须统一
  3. 3,数组的长度在数据运行期间不可改变

1.2 数组的初始化

概念

即在内存中创建一个数组,并且向其中赋予一些默认值

初始化方式

两种常见方式

1,动态初始化(指定长度)

2,静态初始化(指定内容)

动态初始化数组的格式

  1. 数据类型 [] 数组名称 = new 数据类型 [数组长度];

静态初始化基本格式

  1. 数据类型[] 数组名称 = new 数据类型[] {元素A 元素B 元素C,...};

解释含义

  • 左侧数据类型:数组中存放的数据的数据类型
  • 左侧的中括号:代表我是一个数组
  • 左侧数组名称:给数组去一个名字
  • 右侧的new:代表创建数组的动作
  • 右侧数据类型:必须和左侧数据类型一致
  • 右侧中括号的长度:即数组当中,可以存放的数据个数,是一个int类型数字
  1. public class Demo01Array {
  2. public static void main(String[] args) {
  3. // 创建一个数组,里面可以存放200个int数据
  4. // 数据类型 [] 数组名称 = new 数据类型 [数组长度];
  5. int[] arrayA = new int[200];
  6. // 创建一个数组,里面可以存放10个doyble数据
  7. double[] arrayB = new double[10];
  8. // 创建一个数组,里面可以存放20个字符串
  9. String[] arrayC = new String[20];
  10. }
  11. }

两者区别

动态初始化(指定长度):在创建数组的时候,直接指定数组当中的数据元素个数

静态初始化(指定内容):在创建数组的时候,不直接指定数组个数的多少,而是将具体的数据内容进行指定

注意事项

虽然静态初始化没有直接告诉长度,但是根据大括号中元素的具体内容,也可以自动推算出长度

  1. public class Demo02Array {
  2. public static void main(String[] args) {
  3. // 创建一个数组,里面装的全是int数字,具体为:5,15, 25
  4. int[] ArrayA = new int[] { 5, 15, 25 };
  5. // 创建一个数组,里面装的全是字符串,具体为:“Hello”,“World”,“java”
  6. String[] ArrayB = new String[] { "Hello", "World", "Java" };
  7. }
  8. }

静态初始化的省略格式

  1. // 标准格式:
  2. 数据类型[] 数组名称 = new 数据类型[] {元素A 元素B 元素C,...};
  3. // 省略格式:
  4. 数据类型[] 数组名称 = {元素A 元素B 元素C,...};

注意事项

1,静态初始化没有直接指定长度,但是仍然会自动推算得到长度

2,静态初始化标准格式可以拆分成两个步骤

3,动态初始化也可以拆分成两个步骤

4,静态初始化一旦采用省略格式,就不能拆分成两个步骤

使用建议:

如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化

  1. public class Demo03Array {
  2. public static void main(String[] args) {
  3. // 省略格式静态初始化
  4. int[] arrayA = { 10, 20, 30 };
  5. // 静态初始化的标准格式,可以拆分成两个部分
  6. int[] arrayB;
  7. arrayB = new int[] { 11, 21, 31 };
  8. // 动态初始化也可以拆分成两个部分
  9. int[] arrayC;
  10. arrayC = new int[3];
  11. // 静态初始化的省略部分,不可以拆分成两个步骤
  12. // int[] arrayD;
  13. // arrayD = { 10, 20, 30 };
  14. }
  15. }

1.3 数组的访问

直接打印

直接打印数组名称,得到的是数组对应的:内存地址哈希

  • [I@50cbc42f

    • [ —> 代表他是个数组
    • I —> 代表数组中数据类型为int
    • 50cbc42f —> 十六进制地址值

正确访问格式

访问数组元素的格式:数组名(索引值);

索引值:就是一个int数字,代表数组当中元素编号

【注意】索引值从0开始,一直到“数组的长度 - 1”为止

  1. public class Demo04ArrayUse {
  2. public static void main(String[] args) {
  3. // 静态初始化省略格式
  4. int[] array1 = { 10, 20, 30 };
  5. System.out.println(array1); // [I@50cbc42f
  6. // 直接打印数组当中元素
  7. System.out.println(array1[0]); // 10
  8. System.out.println(array1[1]); // 20
  9. System.out.println(array1[2]); // 30
  10. System.out.println("=====================");
  11. // 循环打印数组当中元素
  12. for (int i = 0; i < 3; i++) {
  13. System.out.println(array1[i]);
  14. }
  15. System.out.println("=====================");
  16. // 也可以将数组当中某一个单一元素,赋值交给变量
  17. int sum = array1[1];
  18. System.out.println(sum); //20
  19. }
  20. }

1.4 数组的默认值

默认值

使用动态初始化数组的时候,其中元素将会自动拥有一个默认值。规则如下:

  • 如果是整数类型,那么默认为0;
  • 如果是浮点类型,那么默认为0.0;
  • 如果是字符类型,那么默认为’\u0000’;
  • 如果是布尔类型,那么默认为false;
  • 如果是引用类型,那么默认为null。

注意事项

  • 静态初始化其实也有默认值的过程,只不过系统马上将默认值替换成为大括号当中的具体数值
  1. public class Demo05ArrayUse {
  2. public static void main(String[] args) {
  3. // 动态初始化一个地址
  4. int[] array1 = new int[3];
  5. System.out.println(array1); // 内存地址值
  6. System.out.println("整数类型默认值");
  7. System.out.println(array1[0]); // 0
  8. System.out.println(array1[1]); // 0
  9. System.out.println(array1[2]); // 0
  10. System.out.println("=============");
  11. // 将数据123赋值交给数组array1中的1号元素
  12. array1[1] = 123;
  13. System.out.println(array1[0]); // 0
  14. System.out.println(array1[1]); // 0
  15. System.out.println(array1[2]); // 0
  16. System.out.println("=============");
  17. double[] array2 = new double[1];
  18. System.out.println("浮点类型默认值");
  19. System.out.println(array2[0]); // 0.0
  20. System.out.println("=============");
  21. char[] array3 = new char[1];
  22. System.out.println("字符类型默认值");
  23. System.out.println(array3[0]); // ’/u0000‘
  24. System.out.println("=============");
  25. boolean[] array4 = new boolean[1];
  26. System.out.println("布尔类型默认值");
  27. System.out.println(array4[0]); // false
  28. System.out.println("=============");
  29. System[] array5 = new System[1];
  30. System.out.println("整数类型默认值");
  31. System.out.println(array5[0]); // null
  32. }
  33. }

第二章数组原理内存图

2.1内存概述

内存是计算机中的重要原件,临时存储区域,作用是运行程序。我们编写的程序是存放在硬盘中的,在硬盘中的程 序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。 Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。

2.2 Java虚拟机的内存划分

Java的内存需费划分成为5个部分:

1.栈(Stack) : 存放的都是方法中的局部变量。方法的运行一定要在栈当中运行

  • 局部变量:方法的参数,或者是方法0内部的变量
  • 作用域:一旦超出作用域,立刻从栈内存当中消失。

2.堆(Heap) : 凡是new出来的东西,都在堆当中。

  • 堆内存里面的东西都有一个地址值:16进制
  • 堆内存里面的数据,都有默认值。规则:

    • 如果是整数 默认为0
    • 如果是浮点数 默认为0.0
    • 如果是字符 默认为’\u00oo’
    • 如果是布尔 默认为false
    • 如果是引用类型 默认为null

3.方法区(Method Area) : 存储.class相关信息,包含方法的信息。

4.本地方法栈(Native Method Stack) : 与操作系统相关。

5.寄存器(pc Register) : 与CPU相关。

2.3数组在内存中的存储

一个数组内存图

5.0 数组 - 图1

栈:存储局部变量

堆:存储new出来的东西

方法区:存储.class相关信息

流程

程序想要运行必须要一个.class文件,不能直接运行.java文件,必须需要.class文件,Demo01ArrayOne.class中包含main方法,java会将main方法的相关信息(名字、参数,返回值)保存至方法区

运行时会先查看方法区是否有main方法,有则将他的信息加载到栈,即为main方法在栈中开辟一块内存空间,这本步骤称为入栈

运行时发现在main方法中创建了一个局部变量——数组array,并对其进行了赋值;由于赋值方式为new,会将数组存放到堆中,在堆中开辟一块内存,存放数组的值的相关信息(地址值(16进制,0x代表16进制的值),索引值,数值或默认值),地址值将会被赋值到栈中,放在所属局部变量的后面

注意:new出来的数组实际时存放在堆中,栈中的局部变量存放的只是一个16进制的地址值,

但我们可以通过地址值找到这个数组,比如 System.out.println(array[0]);

  1. 第一步:通过局部变量array中的地址值找到数组
  2. 第二步:通过索引值”0“就可以找到对应的值,并对其进行修改或赋值

最后,数组的数值会改变,但地址值不会改变

重新运行程序时,地址值可能会改变

  1. public static void main(String[] args) {
  2. int[] array = new int[3]; // 动态地址初始化
  3. System.out.println(array); // 地址值
  4. System.out.println(array[0]); // 0
  5. System.out.println(array[1]); // 0
  6. System.out.println(array[2]); // 0
  7. System.out.println("================");
  8. array[1] = 10;
  9. array[2] = 20;
  10. System.out.println(array); // 地址值
  11. System.out.println(array[0]); // 0
  12. System.out.println(array[1]); // 10
  13. System.out.println(array[2]); // 20
  14. }

两个数组内存图

5.0 数组 - 图2

两个数组之间不会相互影响

  1. public class Demo02ArrayTwo {
  2. public static void main(String[] args) {
  3. int[] arrayA = new int[3]; // 动态地址初始化
  4. System.out.println(arrayA); // 地址值
  5. System.out.println(arrayA[0]); // 0
  6. System.out.println(arrayA[1]); // 0
  7. System.out.println(arrayA[2]); // 0
  8. System.out.println("================");
  9. arrayA[1] = 10;
  10. arrayA[2] = 20;
  11. System.out.println(arrayA); // 地址值
  12. System.out.println(arrayA[0]); // 0
  13. System.out.println(arrayA[1]); // 10
  14. System.out.println(arrayA[2]); // 20
  15. int[] arrayB = new int[3]; // 动态地址初始化
  16. System.out.println(arrayB); // 地址值
  17. System.out.println(arrayB[0]); // 0
  18. System.out.println(arrayB[1]); // 0
  19. System.out.println(arrayB[2]); // 0
  20. System.out.println("================");
  21. arrayB[1] = 100;
  22. arrayB[2] = 200;
  23. System.out.println(arrayB); // 地址值
  24. System.out.println(arrayB[0]); // 0
  25. System.out.println(arrayB[1]); // 100
  26. System.out.println(arrayB[2]); // 200
  27. }
  28. }

两个变量指向一个数组

5.0 数组 - 图3

先创建了局部变量arrayA,然后将arrayA的地址值交给arrayB,arrayB对其中的数值进行修改,

由于array A和arrayB共用一个地址值,所以arrayA的数值也发生了改变

  1. public class Demo03ArraySame {
  2. public static void main(String[] args) {
  3. int[] arrayA = new int[3]; // 动态地址初始化
  4. System.out.println(arrayA); // 地址值
  5. System.out.println(arrayA[0]); // 0
  6. System.out.println(arrayA[1]); // 0
  7. System.out.println(arrayA[2]); // 0
  8. System.out.println("================");
  9. arrayA[1] = 10;
  10. arrayA[2] = 20;
  11. System.out.println(arrayA); // 地址值
  12. System.out.println(arrayA[0]); // 0
  13. System.out.println(arrayA[1]); // 10
  14. System.out.println(arrayA[2]); // 20
  15. System.out.println("================");
  16. int[] arrayB = arrayA; // 将arrayA的地址值赋值给arrayB
  17. System.out.println(arrayB); // 地址值
  18. System.out.println(arrayB[0]); // 0
  19. System.out.println(arrayB[1]); // 10
  20. System.out.println(arrayB[2]); // 20
  21. System.out.println("================");
  22. arrayB[1] = 100;
  23. arrayB[2] = 200;
  24. System.out.println(arrayB); // 地址值
  25. System.out.println(arrayB[0]); // 0
  26. System.out.println(arrayB[1]); // 100
  27. System.out.println(arrayB[2]); // 200
  28. System.out.println("================");
  29. System.out.println(arrayA); // 地址值
  30. System.out.println(arrayA[0]); // 0
  31. System.out.println(arrayA[1]); // 100
  32. System.out.println(arrayA[2]); // 200
  33. }
  34. }

第三章数组的常见操作

3.1数组越界异常

索引:

  1. 数组的索引编号从0开始,一直到“数组的长度-1”为止

概述

如果访问数组元素的时候,索引编号不存在,那么将会发生

数组索引越界异常(ArrayIndexOutOfBoundsException)

原因

  1. 索引编号写错了

解决

  1. 修改成为正确索引编号
  1. public class Demo01ArrayIndex {
  2. public static void main(String[] args) {
  3. int[] arrayA = {15, 25, 35};
  4. System.out.println(arrayA[0]); // 15
  5. System.out.println(arrayA[1]); // 25
  6. System.out.println(arrayA[2]); // 35
  7. // 错误写法,数组索引编号不存在
  8. // System.out.println(arrayA[3]); // 35
  9. // System.out.println(arrayA[-1]); // 35
  10. }
  11. }

3.2数组空指针异常

所用引用类型变量,都可以赋值为一个null值。但是代表其中什么也没有

数组必须进行new初始化才能使用其中元素,如果只是赋值了一个null,没有进行new创建数值,

直接访问其中数值,那么将会发生:

空指针异常(NullPointerException)

原因:忘了new

解决:补上new

  1. public class Demo02ArrayNull {
  2. public static void main(String[] args) {
  3. int[] array;
  4. // array = new int[3];
  5. array = null;
  6. System.out.println(array);
  7. // System.out.println(array[0]);
  8. }
  9. }

3.3数组的长度

读取数组长度,格式:

  1. **数组名称.length**<br />
  2. 这将会得到一个int数字,代表数组的长度

注意:

  1. **数组一旦创建,程序运行期间,长度不可改变**

5.0 数组 - 图4

程序中arrayC数组两次输出的长度、地址值不一样是因为,一次将有3个元素的数组的地址值为 [I@50cbc42f 的地址值交给arrayC,

一次将有5个元素的数组的地址值为 [I@75412c2f的地址值交给arrayC。名字没变,但地址值发生了改变

  1. public class Demo03ArrayLength {
  2. public static void main(String[] args) {
  3. int[] arrayA = new int[3];
  4. System.out.println(arrayA.length); // 3
  5. int[] arrayB = { 1, 3, 4, 4, 5, 555, 6632, 34, 434, 24, 234, 5, 67, 234, 55 };
  6. System.out.println(arrayB.length); // 15
  7. int[] arrayC = new int[3];
  8. System.out.println(arrayC); // [I@50cbc42f
  9. System.out.println(arrayC.length); // 3
  10. arrayC = new int[5];
  11. System.out.println(arrayC); // [I@75412c2f
  12. System.out.println(arrayC.length); // 5
  13. }
  14. }

3.4数组遍历【重点】

遍历数组:

  1. 说的就是对数组中的每一个元素进行逐一,挨个处理。默认的方式就是打印输出
  2. idea偷懒写法—— "数组名.fori" 然后回车
  1. public class Demo04Array {
  2. public static void main(String[] args) {
  3. int[] arrayA = {12, 23, 34, 45, 56, 67, 78, 87};
  4. // 首先使用原始方式
  5. System.out.println(arrayA[0]); // 12
  6. System.out.println(arrayA[1]); // 23
  7. System.out.println(arrayA[2]); // 34
  8. System.out.println(arrayA[3]); // 45
  9. System.out.println(arrayA[4]); // 56
  10. System.out.println(arrayA[5]); // 67
  11. System.out.println(arrayA[6]); // 78
  12. System.out.println("===================");
  13. // 使用for循环,次数为数组的长度 8.fori
  14. for (int i = 0; i < 7; i++) {
  15. System.out.println(arrayA[i]);
  16. }
  17. System.out.println("===================");
  18. // 使用for循环,次数为数组的长度 arrayA.fori
  19. for (int i = 0; i < arrayA.length; i++) {
  20. System.out.println(arrayA[i]);
  21. }
  22. }
  23. }

3.5数组获取最大值元素

for循环中使用if进行判断,获取最大值元素

  1. package JavaRunMen.Java05.demo03;
  2. public class Demo05ArrayMax {
  3. public static void main(String[] args) {
  4. int[] arrayB = {7, 67, 31, 84, 32, 15, 5, 18, 82, 78, 50, 30, 68, 11, 34, 45, 12, 25, 71, 62};
  5. int max =arrayB[0];
  6. for (int i = 0; i < arrayB.length; i++) {
  7. if (arrayB[i] > max) {
  8. max = arrayB[i];
  9. }
  10. }
  11. System.out.println("arrayB数组的最大值是"+max);
  12. }
  13. }

3.6数组反转

5.0 数组 - 图5

  1. package JavaRunMen.Java05.demo03;
  2. /*
  3. * 数组元素反转:
  4. * 本来的样子:[1, 2, 3, 4]
  5. * 之后的样子:[4, 3, 2, 1]
  6. *
  7. * 要求:不能使用新数组,就用原来唯一一个数组
  8. * */
  9. public class Demo07ArrayReverse {
  10. public static void main(String[] args){
  11. int[] arrayA = {2, 8, 10, 11, 26};
  12. for (int i = 0; i < arrayA.length; i++) {
  13. System.out.println(arrayA[i]);
  14. }
  15. /*
  16. * 初始化语句:int min = 0, max = arrayA.length-1
  17. * 条件判断语句:min < max
  18. * 步进表达式:min++, min--
  19. * 循环体:用第三个变量倒手
  20. * */
  21. for (int min = 0, max = arrayA.length-1; min < max; min++, max--) {
  22. int temp = arrayA[min];
  23. arrayA[min] = arrayA[max];
  24. arrayA[max] = temp;
  25. }
  26. System.out.println("====================================");
  27. for (int i = 0; i < arrayA.length; i++) {
  28. System.out.println(arrayA[i]);
  29. }
  30. // 自己写的
  31. // int[] arrayA = {2, 8, 10, 11, 25, 26};
  32. // for (int i = 0; i < arrayA.length/2; i++) {
  33. // int temp = arrayA[i];
  34. // arrayA[i] = arrayA[arrayA.length - 1 - i];
  35. // arrayA[arrayA.length - 1 - i] = temp;
  36. // }
  37. // for (int i = 0; i < arrayA.length; i++) {
  38. // System.out.println(arrayA[i]);
  39. // }
  40. }
  41. }

第四章数组作为方法参数和返回值

4.1数组作为方法参数

数组可以作为方法的参数

当调用方法的时候,向方法的小括号进行传参,传递进去的其实是数组的地址值

  1. package JavaRunMen.Java05.Demo04;
  2. /*
  3. * 数组可以作为方法的参数
  4. * 当调用方法的时候,向方法的小括号进行传参,传递进去的其实是数组的地址值
  5. * 然后方法会根据地址值进行相应的操作
  6. *
  7. * */
  8. public class Demo01ArrayParam {
  9. public static void main(String[] args) {
  10. int[] arrayA = {1, 4, 5, 7, 12};
  11. System.out.println(arrayA); // 地址值
  12. printArray(arrayA); // 传递进去的是arrayA当中保存的地址值
  13. System.out.println("===========AAA===========");
  14. printArray(arrayA);
  15. System.out.println("===========BBB===========");
  16. printArray(arrayA);
  17. }
  18. /*
  19. * 三要素
  20. * 返回值类型:只是进行打印而已,不需要进行计算,也没有结果,用void
  21. * 方法名称:printArray
  22. * 参数列表:必须给我数组,才能打印其中元素。int[] array
  23. * */
  24. public static void printArray(int[] array) {
  25. System.out.println("printArray方法收到的参数是");
  26. System.out.println(array);
  27. for (int i = 0; i < array.length; i++) {
  28. System.out.println(array[i]);
  29. }
  30. }
  31. }

4.2数组作为方法返回值

使用一个数组作为返回值类型,可以返回多个数据结果

数组作为方法的参数,传递进去的其实是数组的地址值

数组作为方法的返回值,返回的其实也是数组的地址值

  1. package JavaRunMen.Java05.Demo04;
  2. /*
  3. * 一个方法可以有0、1、2、多个参数,但只能有0或者1个返回值,不能有多个返回值
  4. * 如果希望一个方法当中产生多个结果数据进行返回,怎么办?
  5. * 解决方案:使用一个数组作为返回值类型即可
  6. *
  7. * 任何数据类型都能作为方法的参数类型、或者返回类型
  8. *
  9. * 数组作为方法的参数,传递进去的其实是数组的地址值。
  10. * 数组作为方法的返回值,返回的其实也是数组的地址值。
  11. * */
  12. public class Demo02ArrayReturn {
  13. public static void main(String[] args) {
  14. int[] result = calculate(10, 20,30);
  15. System.out.println("main方法接受到的数组是");
  16. System.out.println(result); // 地址值
  17. System.out.println("总和:" + result[0]);
  18. System.out.println("平均数:" + result[1]);
  19. }
  20. public static int[] calculate (int a, int b, int c) {
  21. int sum = a + b +c; // 总和
  22. int avg = sum / 3; // 平均数
  23. // 两个结果希望进行返回
  24. // 需要一个数组,也就是一个塑料袋,数组可以保存多个结果
  25. /*
  26. * int[] array = new int[2];
  27. * array[0] = sum // 总和
  28. * array[1] = avg // 平均数
  29. *
  30. * */
  31. int[] array = {sum, avg};
  32. System.out.println("calculate方法内部数组是");
  33. System.out.println(array); // 地址值
  34. return array;
  35. }
  36. }

4.3方法的参数类型区别

方法的参数为基本类型时,传递的是数据值. 方法的参数为引用类型时,传递的是地址值

  1. package JavaRunMen.Java05.Demo04;
  2. public class Demo03ArrayParameter {
  3. public static void main(String[] args) {
  4. int a = 1, b = 2;
  5. System.out.println("向方法中传入基本类型的数据");
  6. System.out.println("传入前");
  7. System.out.println(a);
  8. System.out.println(b);
  9. System.out.println("===========================");
  10. System.out.println("方法中");
  11. change(a,b);
  12. System.out.println("===========================");
  13. System.out.println("传入后");
  14. System.out.println(a);
  15. System.out.println(b);
  16. System.out.println("===========================");
  17. int [] arrayA = {1, 3, 5};
  18. System.out.println("向方法中传入引用类型的数据");
  19. System.out.println("传入前");
  20. System.out.println(arrayA[0]);
  21. System.out.println("===========================");
  22. System.out.println("方法中");
  23. change1(arrayA);
  24. System.out.println("===========================");
  25. System.out.println("传入后");
  26. System.out.println(arrayA[0]);
  27. System.out.println("===========================");
  28. System.out.println("方法的参数为基本类型时,传递的是数据值. 方法的参数为引用类型时,传递的是地址值");
  29. }
  30. public static void change(int a, int b) {
  31. a = a + b;
  32. b = a + b;
  33. System.out.println(a);
  34. System.out.println(b);
  35. }
  36. public static void change1(int[] array) {
  37. array[0] = 200;
  38. System.out.println(array[0]);
  39. }
  40. }