A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 xiekai_sjz 于 2018-9-7 15:49 编辑

day05 数组       数组是java语言中重要的数据结构之一,是用来存储固定大小的同类型元素。今天我们来详细的学习下数组的相关知识。
    以下是今天的学习目标:
  • 理解容器的概念
  • 掌握数组的第一种定义方式
  • 掌握数组的第二种定义方式
  • 掌握数组的第三种定义方式
  • 使用索引访问数组的元素
  • 了解数组的内存图解
  • 了解空指针和越界异常
  • 掌握数组的遍历
  • 掌握数组最大值的获取
  • 了解数组反转的原理
  • 了解数组作为方法参数传递
  • 了解数组作为方法的返回值



    以下是今天的详细笔记:

数组的定义和访问数组的概念
数组: 是一种容器, 可以同时存放同一种类型的多个数据值
数组的特点:
    1. 是一种引用数据类型
    2. 数组中的多个数据,类型必须统一
    3. 数组的长度在程序运行期间不可改变
数组的定义格式一: 动态初始化
数组的初始化: 在内存当中创建一个数组, 并且向其中赋予一些默认值

两种常见的初始化方式:
    1. 动态初始化: 指定长度
    2. 静态初始化: 指定内容

动态初始化数组的格式:
        数据类型[] 数组名称 = new 数据类型[数组长度];

        数据类型 变量名 = 初始化值;

    int[] arr1 = new int[3];
    String[] arr2 = new String[10];

    解析含义:
        左侧数据类型:也就是数组当中保存的数据,全都是统一的什么类型
        左侧的中括号:代表是一个数组
        左侧数组名称:给数组取一个名字
        右侧的new:代表创建数组的动作
        右侧数据类型:必须和左边的数据类型保持一致
        右侧中括号的长度:也就是数组当中,到底可以保存多少个数据,是一个int数字
[Java] 纯文本查看 复制代码
// 完成以下要求:
// 定义一个长度为2的元素为char类型的数组
char[] arr = new char[2];

// 定义一个长度为5的元素为double类型的数组
double[] arr = new double[5];

// 定义一个长度为8的元素为字符串类型的数组
String[] arr = new String[8];

// 定义一个长度为0的元素为boolean类型的数组
boolean[] arr = new boolean[0];

数组的定义格式二: 静态初始化
静态初始化基本格式:
        数据类型[] 数组名称 = new 数据类型[] { 元素1, 元素2, ... };

    int[] arr1 = new int[]{1, 2, 3};
    String[] arr2 = new String[]{"Hello", "World", "Java"};
[Java] 纯文本查看 复制代码
// 完成以下要求
// 定义一个数组, 存放 'a', 'b', 'c'
char[] arr = new char[]{'a', 'b', 'c'};   // 长度3

// 现有3个学生的分数: 100.0, 95.5, 87.5 用什么容器装? 怎么写?
double[] arr = new double[]{100.0, 95.5, 87.5};

数组的定义格式三: 省略的静态初始化
静态初始化省略格式:
    数据类型[] 数组名称 = { 元素1, 元素2, ... };

    int[] arr1 = {1, 2, 3};
    String[] arr2 = {"Hello", "World", "Java"};

注意事项:
    1. 静态初始化没有直接指定长度,但是仍然会自动推算得到长度。
    2. 静态初始化标准格式可以拆分成为两个步骤。
    3. 动态初始化也可以拆分成为两个步骤。
    4. 静态初始化一旦使用省略格式,就不能拆分成为两个步骤了。

    // 动态初始化可以拆分为2步
    int[] arrayC;
    arrayC = new int[5];

    // 静态初始化不能拆分为2步
    int[] arrayD;
    arrayD = {10, 20, 30};  // 报错

初始化方式建议:
        不确定数组当中的具体内容, 用动态初始化
        确定了具体的内容, 用静态初始化
访问数组元素: 获取元素值
索引: 就是一个int数字, 代表数组当中元素的编号
        索引值从0开始, 一直到数组的长度-1为止

访问数组元素的格式:
        数组名称[索引值]
[Java] 纯文本查看 复制代码
// 说出答案
int[] array = {10, 20, 30};  // 长度为3
//     索引为?  0   1   2
System.out.println(array[0]); // 输出?10
int num = array[1];
System.out.println(num);      // 输出?20

// 直接打印数组名, 输出数组的地址值
System.out.println(array); // [I@75412c2f  数组的内存地址的哈希值

5分钟练习: 获取数组元素并打印
需求: 定义一个长度为3的int数组, 获取所有元素打印出来
代码:
[Java] 纯文本查看 复制代码
/*
需求: 定义一个长度为3的int数组, 获取所有元素打印出来
 */
public class Test {
    public static void main(String[] args) {
        // 动态初始化定义数组
        int[] arr = new int[3];

        // 通过索引获取元素值: 数组名[索引]
        System.out.println(arr[0]);  // 0
        System.out.println(arr[1]);  // 0
        System.out.println(arr[2]);  // 0
    }
}

访问数组元素: 为元素赋值
为元素赋值:        数组名[索引] = 值;        arr[0] = 10;数组初始化时, 元素有一个默认值    byte, short, int, long: 0    float,  double: 0.0    char: '\u0000'    boolean: false    引用数据类型: null注意事项:        静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成为了大括号当中的具体数值
5分钟练习: 使用数组需求:
使用动态初始化创建元素为int, 长度为3的数组arr1, 打印数组中所有的元素值, 然后将所有元素赋值为6, 再次获取所有元素打印
代码:
[Java] 纯文本查看 复制代码
/*
需求:
使用动态初始化创建元素为int, 长度为3的数组arr1,
打印数组中所有的元素值,
然后将所有元素赋值为6,
再次获取所有元素打印
 */
public class Test {
    public static void main(String[] args) {
        // 使用动态初始化创建元素为int, 长度为3的数组arr1
        int[] arr1 = new int[3];

        // 打印数组中所有的元素值
        System.out.println(arr1[0]);  // 0
        System.out.println(arr1[1]);  // 0
        System.out.println(arr1[2]);  // 0

        // 然后将所有元素赋值为6
        arr1[0] = 6;
        arr1[1] = 6;
        arr1[2] = 6;

        // 再次获取所有元素打印
        System.out.println(arr1[0]);  // 6
        System.out.println(arr1[1]);  // 6
        System.out.println(arr1[2]);  // 6
    }
}

数组原理内存图Java中的内存划分
Java对于内存划分的5个区域:
    1. 栈(Stack): 存放被调用的方法和方法中的局部变量
       局部变量: 定义在方法中的变量
       垃圾回收时机: 一旦超出作用域, 立即被回收
    2. 堆(Heap): 存放new出来的对象
       每个new出来的对象都有一块新的内存空间, 并拥有一个地址值
       堆内存中的数据, 都有默认值
       垃圾回收时机: 当该对象没有引用时, 垃圾回收器会在空闲时回收该对象的内存
    3. 方法区(Method Area): 存放class字节码对象, 字节码对象中包含方法的信息, 常量池
    4. 本地方法栈(Native Method Stack): 与操作系统相关
    5. 寄存器(PC Register): 与CPU相关


内存图示

栈          堆
+-----+    +-----+
|         |      |       |
|         |      |       |
|         |      |       |
+-----+    +-----+
方法区
+----------------+
|                         |
+----------------+

补充:
内存垃圾回收:
        回收原因: 我们创建的每个变量或数组, 都是占用一部分内存空间来存储数据的. 如果程序占用的内存不被释放掉, 最终会将内存占满, 导致无法继续运行程序. 所以需要回收不用的内存空间. 不再使用的内存空间, 就被看作"垃圾"进行回收
        栈: 局部变量一旦超出作用域立即回收; 调用的方法执行完毕立即回收
        堆: 当创建的对象没有任何变量引用后, 在垃圾回收器空闲时, 会被垃圾回收器回收

一个数组的内存图
[Java] 纯文本查看 复制代码
public class Demo01ArrayOne {

    public static void main(String[] args) {
        int[] array = new int[3];     // 
        System.out.println(array);    // 
        System.out.println(array[0]); // 
        System.out.println(array[1]); // 
        System.out.println(array[2]); // 
        System.out.println("==============");

        // 改变数组当中元素的内容
        array[1] = 10;
        array[2] = 20;
        
        System.out.println(array);    // 
        System.out.println(array[0]); // 
        System.out.println(array[1]); // 
        System.out.println(array[2]); // 
    }
}

执行流程:
    运行程序
        * 先将`Demo01ArrayOne.class`字节码文件, 加载到`方法区`中, 成为`字节码对象`
        * 然后找到该字节码对象中的`main()`方法, 加载到`栈`中执行方法, 方法执行时也会占用`栈`中的内存空间
    int[] array = new int[3];: 定义数组类型的变量, 并初始化数组对象
        1. `int[] array`: 在`栈`内存中, 定义了一个int数组类型的变量array
            * 开辟了一块内存空间
        2. `new int[3]`: 在`堆`内存中, 创建了一个int数组类型对象
            * 开辟了3块连续的内存空间. 该数组空间拥有一个地址值
            * 空间有索引
            * 元素有默认值
        3. `int[] array = new int[3];`: 将右边数组对象的地址值, 赋值给左边int数组类型的变量. 所以变量保存的实际是地址值
    System.out.println(array[1]);: 数组通过索引获取元素值.
        * array是局部变量, 先在栈中找到该局部变量, 找到其中保存的地址值
        * 然后根据地址值, 找到堆内存中的数组对象的内存空间
        * 然后根据索引, 找到数组中指定的元素
        * 返回元素值
        * 打印
    array[1]  = 10;: 数组通过索引给元素赋值.
        * array是局部变量, 先在栈中找到该局部变量, 找到其中保存的地址值
        * 然后根据地址值, 找到堆内存中的数组对象的内存空间
        * 然后根据索引, 找到数组中指定的元素
        * 修改替换元素的值

两个数组的内存图
[Java] 纯文本查看 复制代码
public class Demo02ArrayTwo {

    public static void main(String[] args) {
            // 创建第一个数组
        int[] arrayA = new int[3];
        System.out.println(arrayA);    // 
        System.out.println(arrayA[0]); // 
        System.out.println(arrayA[1]); // 
        System.out.println(arrayA[2]); // 
        System.out.println("==============");

        arrayA[1] = 10;
        arrayA[2] = 20;
        
        System.out.println(arrayA);    // 
        System.out.println(arrayA[0]); // 
        System.out.println(arrayA[1]); // 
        System.out.println(arrayA[2]); // 
        System.out.println("==============");

                // 创建第二个数组
        int[] arrayB = new int[3];
        
        System.out.println(arrayB);    // 
        System.out.println(arrayB[0]); // 
        System.out.println(arrayB[1]); // 
        System.out.println(arrayB[2]); // 
        System.out.println("==============");

        arrayB[1] = 100;
        arrayB[2] = 200;
        
        System.out.println(arrayB);    // 
        System.out.println(arrayB[0]); // 
        System.out.println(arrayB[1]); // 
        System.out.println(arrayB[2]); // 
    }
}


两个引用指向同一个数组的内存图
[Java] 纯文本查看 复制代码
public class Demo03ArraySame {

    public static void main(String[] args) {
            // 创建一个数组
        int[] arrayA = new int[3];
        System.out.println(arrayA);    // 
        System.out.println(arrayA[0]); // 
        System.out.println(arrayA[1]); // 
        System.out.println(arrayA[2]); // 
        System.out.println("==============");

        arrayA[1] = 10;
        arrayA[2] = 20;
        
        System.out.println(arrayA);    // 
        System.out.println(arrayA[0]); // 
        System.out.println(arrayA[1]); // 
        System.out.println(arrayA[2]); // 
        System.out.println("==============");

        // 将arrayA数组的地址值,赋值给arrayB数组
        int[] arrayB = arrayA;         // 
        
        System.out.println(arrayB);    // 
        System.out.println(arrayB[0]); // 
        System.out.println(arrayB[1]); // 
        System.out.println(arrayB[2]); // 
        System.out.println("==============");

        arrayB[1] = 100;
        arrayB[2] = 200;
        System.out.println(arrayB);    // 
        System.out.println(arrayB[0]); // 
        System.out.println(arrayB[1]); // 
        System.out.println(arrayB[2]); // 
    }
}


补充: 内存就类似于Excel中的表格, 划分为不同的单元格, 一个格子个地址
        变量就是一个单元格, 可以存一个数据.
        数组就是连续的多个格子


数组索引为什么设计为从0开始?
        数组对象的地址值, 其实就是数组中存放第一个元素的内存地址值
        数组中的元素是连续的内存空间
        数组中的索引, 其实就是相对于第一个元素地址值的"偏移量"
        找到数组中的其他元素, 是通过 "第一个元素地址值 + 偏移量" 找到的
        arr[0] 就是 0xF5 + 0 = 0xF5
        arr[1] 就是 0xF5 + 1 = 0xF6
        arr[2] 就是 0xF5 + 2 = 0xF7

数组的异常和练习常见问题: 数组索引越界异常ArrayIndexOutOfBoundsException: 数组索引越界异常
        发生原因: 访问了不存在的索引
        解决方法: 不要访问不存在的索引
补充:
      异常发生的线程                    异常的类型                       异常发生的说明___________/\____________  ________________/\______________________  _______/\_________Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3        at cn.itcast.day05.demo03.Demo01ArrayIndex.main(Demo01ArrayIndex.java:15)        ----------------------------------------------- ------------------------               异常发生的所在包, 类, 方法                  异常发生所在的文件及行号               异常是一种安全消息机制, 可以帮助开发者快速定位错误看到异常不要慌, 从上往下找到自己包名的一行, 点击文件行号, 就可以跳转到发生异常的代码根据异常的类型和说明来判断出错的原因, 并修改代码
常见问题: 空指针异常
NullPointerException: 空指针异常
        发生原因:
                数组变量值为null时, 使用数组变量操作索引就会发生
                对象变量值为null时, 使用对象变量调用方法就会发生
        解决方法:
                可以提前判断数组变量或对象是否为null, 不为null再操作
[Java] 纯文本查看 复制代码
// 数组变量值为null
int[] arr = null;
System.out.println(arr[0]);  // NullPointerException
arr[0] = 10;                 // NullPointerException

// 解决方式:
if (arr != null) {
    System.out.println(arr[0]);
        arr[0] = 10;
}

获取数组的长度
数组的长度: 数组中元素的个数
        注意: 数组一旦创建, 长度不可改变

数组长度和最大索引的关系: 最大索引 = 数组长度 - 1
[Java] 纯文本查看 复制代码
int[] arr = new int[5];
int a = arr.length;
System.out.println(a);  // 长度是?

// new int[5]索引为: 0 1 2 3 4, 最大索引为4, 即长度-1

数组的遍历输出
遍历: 依次获取数组的所有元素值

int[] arr = {1,2,3,4,5};

// for循环方式
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr);
}

IDEA快捷键:
        数组名.fori
5分钟练习: 遍历数组
需求: 定义int数组, 元素为1,2,3,4,5. 使用for循环遍历并打印元素
代码:
[Java] 纯文本查看 复制代码
/*
需求: 定义int数组, 元素为1,2,3,4,5. 使用for循环遍历并打印元素
 */
public class Test {
    public static void main(String[] args) {
        // 定义数组, 知道元素, 所以使用静态初始化
        int[] arr = {1,2,3,4,5};
        // for循环遍历  数组名.fori
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

求出数组中的最值**编程思维: 求最大值**
[Java] 纯文本查看 复制代码
int[] arr = {5, 15, 30, 20, 10000};
// 定义变量保存最大值, 先用第一个元素作为参照物
int max = arr[0];
// 遍历获取其他元素比较
for (int i = 1; i < arr.length; i++) {
    // 取出每个元素, 与最大值比较
    if (arr[i] > max) {
        // 如果取出的元素比当前最大值更大, 则将其存入max变量
        max = arr[i];
    }
}
// for循环结束后, max中保存的就是最大值
System.our.println(max);  // 10000

**编程思维: 求最小值**
[Java] 纯文本查看 复制代码
int[] arr = {5, 15, 30, 20, 10000};
// 定义变量保存最小值, 先用第一个元素作为参照物
int min = arr[0];
// 遍历获取其他元素比较
for (int i = 1; i < arr.length; i++) {
    // 取出每个元素, 与最小值比较
    if (arr[i] < min) {
        // 如果取出的元素比当前最小值更小, 则将其存入min变量
        min = arr[i];
    }
}
// for循环结束后, min中保存的就是最大值
System.our.println(min);  // 5

5分钟练习需求: 定义数组{5, 15, 30, 20, 10000}, 分别求数组中的最大值和最小值
代码:
[Java] 纯文本查看 复制代码
/*
需求: 定义数组{5, 15, 30, 20, 10000}, 分别求数组中的最大值和最小值
 */
public class Test {
    public static void main(String[] args) {
        int[] arr = {5, 15, 30, 20, 10000};

        // 获取最大值
        int max = arr[0];
        // 遍历数组, 获取其他元素进行比较
        for (int i = 1; i < arr.length; i++) {
            // 获取一个元素, 与当前max进行比较
            if (arr[i] > max) {
                // 如果当前元素比max还要大, 则将当前值存入max作为最大值
                max = arr[i];
            }
        }
        // for循环结束后, max中保存的就是最大值
        System.out.println("最大值:" + max);  // 10000

        // 获取最小值
        int min = arr[0];
        // 遍历数组, 获取其他元素进行比较
        for (int i = 1; i < arr.length; i++) {
            // 获取一个元素, 与当前min进行比较
            if (arr[i] < min) {
                // 如果当前元素比min还要小, 则将当前值存入min作为最小值
                min = arr[i];
            }
        }
        // for循环结束后, min中保存的就是最小值
        System.out.println("最小值:" + min);  // 5
    }
}

数组元素反转编程思维: 数组元素反转 (在原数组中交换元素)
[Java] 纯文本查看 复制代码
int[] arr = {10, 20, 30, 40, 50};
// 遍历数组, 定义最小索引和最大索引
for (int min = 0, max = arr.length - 1; min < max; min++, max--) {
    // 定义第三个变量用于交换元素值
    int temp = arr[min];
    arr[min] = arr[max];
    arr[max] = temp;
}

5分钟练习:需求: 定义数组{10, 20, 30, 40, 50}, 将元素反转
代码:
[Java] 纯文本查看 复制代码
/*
需求: 定义数组{10, 20, 30, 40, 50}, 将元素反转
 */
public class Test {
    public static void main(String[] args) {
        // 定义数组
        int[] arr = {10, 20, 30, 40, 50};

        // 反转数组
        for (int min = 0, max = arr.length - 1; min < max; min++, max--) {
            // 首尾元素交换
            int temp = arr[min];
            arr[min] = arr[max];
            arr[max] = temp;
        }

        // 打印交换完的数组
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

数组作为方法参数: 传递地址
[AppleScript] 纯文本查看 复制代码
//结论: 数组作为参数传递, 实际传递的是数组对象的地址值

public class Demo01ArrayParam {

    public static void main(String[] args) {
        int[] array = { 10, 20, 30, 40, 50 }; // 0x666
        printArray(array);                    // 0x666
    }

        // 打印数组元素
    public static void printArray(int[] array) {  // 相当于 int[] array = 0x666
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

数组作为方法返回值: 返回地址
[Java] 纯文本查看 复制代码
//结论: 数组作为返回值, 实际返回的是数组对象的地址值

public class Demo02ArrayReturn {

    public static void main(String[] args) {
        int[] result = calculate(10, 20, 30);  // 返回的是地址值 0x666

        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 };  // 0x666
        return array;                // 0x666
    }
}



















5 个回复

倒序浏览
消灭零回复
回复 使用道具 举报
liuyaxiong 来自手机 初级黑马 2018-8-29 18:18:24
藤椅
xiekai_sjz 发表于 2018-8-28 14:35
day05 数组数组的定义和访问数组的概念数组: 是一种容器, 可以同时存放同一种类型的多个数据值

数组的特点 ...

2楼。顶
回复 使用道具 举报
林志博 来自手机 初级黑马 2018-8-29 21:28:18
板凳
笔记用有道云挺好的
回复 使用道具 举报
兄弟加油
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马