AI悦创

V1

2023/01/06阅读:15主题:凝夜紫

20-认识变量和数组

你好,我是悦创。

原文首发:https://bornforthis.cn

0. 目录

  • 重新认识基本类型的变量
  • 认识数组
  • 数组的长度
  • 数组索引过界会出错
  • 让变量代表新的数组

1. 重新认识基本类型的变量

1.1 一个简单的使用变量的程序

import java.util.Scanner;

public class UseVariable {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        int a;
        System.out.println("创建了变量 a,输入一个整数:");
        a = in.nextInt();
        System.out.println("给 a 赋值,a 的值为" + a + ",请再次输入一个整数:");

        a = in.nextInt();
        System.out.println("再次给赋值,现在 a 的值为" + a);
    }
}

1.2 变量的基本逻辑——有定才有变。在人看来,固定的是名字,变化的是名字对应的值。对计算机来说,固定的是地址,变化的是值

1.3 用人工的方式,模拟一下计算机执行给变量 a 赋值的过程。

1.4 理解计算机如何使用内存,完成变量的功能

  • 内存就是一堆白纸,只能通过页码编号访问,也就是所谓的内存地址。
  • 变量就是使用一个固定的地址加上这个地址对应的内存。计算机通过地址,读写地址对应的内存的值。完成变量的赋值和访问值的功能。就好像可以根据页码编号,在指定的白纸上写字,或者擦掉再复写。
  • 变量的名就是地址,变量的实就是地址的内存的值。

2. 认识数组——名与实

2.1 理解数组的名与实

  • 数组的“实”是一块地址连续的内存,就像是编号连续的一沓白纸。
  • 数组的名,就是这个块连续内存的第一个内存的地址。 「因为,数组是一个连续的数据,所以你确定了第一个,后面的不也就确定了」
  • 数组的变量和基本变量一样,本身是个地址。但是与基本变量不一样的是,这个地址的值,是数组的“名”,也就是数组的第一个地址。
public class WhatArray {
    public static void main(String[] args) {
        int[] book = new int[10];
        // new int[10]: 创建一个大小为10的 int 数组「在小本本上面,连续十页纸,创建 10 int 那么大的内存」。——创建一个数组,把他们绑起来
        // 所以,我们可以在上面标记一下 int[10]
        // 那 book = new int[10] 是什么意思?——这个 book 就是数组的名,这个名就是这个数组第一个位置「小本本的第一页的地址」的物理地址。(也就是说,book 它等于地址。)
        // 所以说,book 本身并不是数组,它只是保存了数组的地址。——也就是 book 指向了数组
    /*int[] book = new int[10];
    两个实体:
        第一个实体数组就是数组本身
        第二个实体就是 book*/


        book[0] = 11;
        book[1] = 11;
        int[] book2 = book;
        System.out.println(book2[0]);
    }


}

2.2 数组=数组变量+数组的实体

  • 数组变量[索引] 就是在数组原有地址的基础上,加上索引,获得想要的元素
  • 所以索引是从 0 开始的,因为数组变量的地址就是数组第一个元素的地址,不需要加

详解: 我用上面的 book 数组来理解。book 本身是个变量,比如这个变量的地址是 6,而这个 book 上面又记录了数组最开始的地址,比如:35。这个时候如果你要输出数组的第一个位置的数据,其实也就是 35 本身。那这个时候,你对 35 + 1 ?合适吗?——你不管写什么都不太合适,所以这个时候直接 35 + 0,也就是本身第一个数据。 总而言之:其实我们查询的数据的时候的数值,其实就是偏移量。所以第一个数据加其他的都不合适,+0 才合适。+1 也就是 35 + 1 ,36 它的下一会数据。「数组是一个连续性的」 这样你就明白了,数组的索引为什么从 0 开始了。

3. 数组的长度

3.1 使用数组的长度

  • 数组变量 .length 可以获得数组的长度
  • 数组创建之后,长度不可以改变
public class AssignArray {
    public static void main(String[] args) {
        int[] array = new int[3];

        array[0] = 9;

        System.out.println("array长度为" + array.length + "。array[0] = " + array[0]);

        array = new int[32];

        System.out.println("array长度为" + array.length + "。array[0] = " + array[0]);
    }
}

4. 数组索引过界和初始值

3.2 数组索引过界和初始值

  • 访问数组过界出错的例子,数组出界的错误叫做 IndexOutOfBoundException
  • 如果没有把握数组是否会出界,可以把索引和数组长度做比较。注意索引是从 0 开始的,不是从 1 开始的
  • 数组里每个元素的都有初始值,初始值和类型有关。对于数字类型,初始值是 0,对于 boolean 类型,初始值是 false。
public class IndexOutOfBoundExample {
    public static void main(String[] args) {
        int[] array = new int[5];
        System.out.println(array[array.length]);
    }
}

输出:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
 at IndexOutOfBoundExample.main(IndexOutOfBoundExample.java:4)

5. 让变量指向新的数组

5.1 让变量指向新的数组

  • 数组变量可以指向新的数组实体。这时候,数组变量的值就是新的数组实体的地址了。这种数组变量的赋值操作,叫做让变量指向新的数组。
  • 如果没有别的数组变量指向原来数组实体,也就是说,如果没有数组变量“记得”原来数组的地址,原来的数组实体就再也不可访问了,也就好像“消失”了。
  • 对于非基本类型的变量,计算机都要通过这种“两级跳”的方式来访问。基本类型变量,一跳就可以。
public class AssignArray {
    public static void main(String[] args) {
        int[] array = new int[3];

        array[0] = 9;

        System.out.println("array长度为" + array.length + "。array[0] = " + array[0]);

        array = new int[32];  // 指向一个 32 的数组,创建一个新的数组

        System.out.println("array长度为" + array.length + "。array[0] = " + array[0]);
    }
}

输出:

array长度为3。array[0] = 9
array长度为32。array[0] = 0

学员评论

这一节挺绕的,大致说说自己的理解。 int a = 1; int[] book = new int[10]; 1. 数组变量名book和基本类型变量名a本质上是一样的,编译后本身是地址(栈地址),存储的是数据,只不过book存储的数据是地址(堆地址),这个地址标识了另一块内存区域(堆内存)。 2. 那么book[0]和book[1]其实也是地址,与a或book不同的是,后者是编译时确定的绝对地址,而前者构建的是与book的相对关系,与编译无关,即book[0]与book地址相同,book[1]为book地址偏移1个int。这也解释了为什么数组第一个元素下标为0。 作者回复: 是我讲的太好,还是你太优秀,关于引用的关系竟然理解的丝毫不差。 稍微有些不准确的是“后者是编译时确定的绝对地址”。这栈内地址也不是编译时确定的。每次调用方法都会给方法分配一段内存作为存储方法中局部变量所用。所以每个变量在这个基础上,也是一个偏移量,这个偏移量对每个变量来说说固定的。比如说a,可能就是8,每次都是栈地址+8是其真正的地址。 其实Java编译完之后,没有什么东西是有绝对内存地址的,中间还隔了一个Java虚拟机呢。即使是本地程序(比如Windows上编译成exe的程序),也不是绝对地址。如果我学的操作系统和汇编语言还没完全扔掉的话,好像只有内核有绝对地址?真实的内存地址有时候要经过好几次相对地址的变化,我记得当时一个基址变址寻址了解一下?

索引,按照偏移量来理解,确实比较好明白了。 作者回复: 嗯呐,下次再有人问为什么你们程序员总喜欢从 0 开始计数,就反问:你知道什么是数组吗?

AI悦创·编程一对一

AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh

C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh

分类:

后端

标签:

Java

作者介绍

AI悦创
V1

编程一对一教学,微信:Jiabcdefh