4.2 java中的数组

什么是数组

我们先来看看这样一个例子,如果一个系统中存储的是一个 Java 工程师信息,假设这个系统需要存储 100 个 Java 工程师信息,难道需要定义 100 个编号变量、100 个姓名变量和 100 个底薪变量吗?显然,编程语言不会这么傻。Java 提供了一种称为数组的数据类型,数组不是基本数据类型,而是引用数据类型。

数组是把相同类型的多个变量按一定顺序组织起来,这些按序排列的同类型数据元素的集合称为数组。数组中的元素在内存中是连续存储的数组中的数据元素既可以是基本类型,也可以是引用类型

在这里插入图片描述

常见的错误类型

语法错误,编译时异常,运行时异常
在这里插入图片描述

数组的创建方法

静态初始化

数组的三种遍历方式

Arrays.toString,for循环,增强for循环
在这里插入图片描述

数组的内存结构

前面学习 Java 基本数据类型的时候提到,Java 数据类型分为两大类,分别是基本数据类型和引用数据类型。内存存储形式的不同是基本数据类型和引用数据类型本质的区别:

引用数据类型的名称实际代表的是存放数据的地址,不是数据本身,基本数据类型反之。如 String name=“颜群”, name 存放的是字符串“颜群”的地址;int age=30; 可认为 age 存放的是数值 30 本身。int[] engNo 中 engNo 是引用数据类型变量,所以其存放的是数组的地址。
Java 的内存分为栈内存和堆内存。基本数据类型的变量和数据都存储在栈中,引用数据类型的变量(地址)存储在栈中,数据存储在堆中,前面说的地址完整地说是“堆内存地址”。
数组不属于基本数据类型(虽然其内部存储的可能是基本数据类型),只能是引用数据类型。因此语句 int[] engNo = new int[]{1001,1002,1003,1004,1005}; 中,数组本身是在堆内存中开辟的空间,该空间的地址存储在栈内存中并命名为 engNo,如图 所示。

在这里插入图片描述
在这里插入图片描述

String类型数组演变过程

之前讲到过,引用的名称实际代表的是存放数据的地址。因此,如果数组中的元素是 String 类型,那么数组元素存放的就是 String 类型的引用即数据的地址

在使用 String[] names = new String[4]; 创建字符串数组时,会在堆内存中分配 4 个连续空间,并把空间地址赋给 names ,使 names 指向这 4 个连续的内存空间。这 4 个空间里存放的默认初始值为 null(String 类型数据的默认值),如图所示。

在这里插入图片描述
names[0] = “王云”; 因为数组的元素是引用类型,因此会将"王云"的地址放到 names 数组的第 1 个元素空间里

之后,依次将"刘静涛", “南天华”, "雷静"的地址存放到 names 中相应的位置,如图所示。

在这里插入图片描述

(重点!)将数组作为参数传递

首先我们还是先创建文件 TestArray2.java 并添加如下代码:

public class TestArray2{

}

设计方法 exchange1(int a, int b) 作用是交换 a 和 b 的值:

  //传递基本数据类型,交换int型a和b的值
    public static void exchange1(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }

设计方法 exchange2(int[] x) 注意,该方法的形参是一个 int 型数组,该方法的作用是交换数组 x 的第 1 个和第 2 个元素的值

   //传递引用数据类型,交换数组x第1个元素和第2个元素的值
    public static void exchange2(int[] x) {
        int temp = x[0];
        x[0] = x[1];
        x[1] = temp;
    }

提供 main 方法,提供实参并对上述两个方法进行调用,完整代码如下:

class TestArray2 {
    public static void main(String[] args) {
        int engNo1 = 1001;
        int engNo2 = 1002;
        System.out.println("传递值交换数值:");
        //调用前
        System.out.println("调用前第1、第2编号为:" + engNo1 + "\t" + engNo2);
        //值传递,传递的实质是数值的副本,所以没有交换原值
        exchange1(engNo1, engNo2);
        //调用后
        System.out.println("调用后第1、第2编号为:" + engNo1 + "\t" + engNo2);

        int[] engNo = new int[2];//数组类型实参
        //给数组赋值
        engNo[0] = 1001;
        engNo[1] = 1002;
        System.out.println("传递引用交换数值:");
        //调用前
        System.out.println("调用前第1、第2编号为:" + engNo[0] + "\t" + engNo[1]);
        //传递引用类型,传递的实质是指向数组的地址,所以交换了数组里的值
        exchange2(engNo);
        //调用后
        System.out.println("调用后第1、第2编号为:" + engNo[0] + "\t" + engNo[1]);
    }

    //传递基本数据类型,交换int型a和b的值
    public static void exchange1(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }

    //传递引用数据类型,交换数组x第1个元素和第2个元素的值
    public static void exchange2(int[] x) {
        int temp = x[0];
        x[0] = x[1];
        x[1] = temp;
    }
}

编译、运行程序,运行结果如下:

图片描述

查看结果我们发现,执行完 exchange1 方法后,原来的 engNo1 和 engNo2 的值没有发生交换,但是执行完 exchange2 方法后,数组 engNo 的第 1 和第 2 个元素的值发生和调换,出现这种情况的原因是:

传递基本数据类型时,其传递的实质是数值的副本,所以在调用使用值传递交换数据的方法时(即调用 exchange1 时),只是在方法内将值的副本的数据内容进行了交换,其原数据本身并没有发生变化。

传递引用数据类型时,其传递的实质为引用的地址,本例中传递的是数组的地址,在调用使用“引用地址”传递交换数据的方法时(即调用 exchange2 时),是对这个地址指向的数据进行了交换,即对原数组的值进行了交换。

**说明,在 Java 中只存在值传递,并不存在引用传递。**有些资料上写的“引用传递”,实际上传递的是引用对象的地址。

例:【练一练】根据加薪标准计算实际薪资

之前的需求如下:

计算出底薪大于等于 6000 元的高薪人员比例以及这些高薪人员的底薪平均值。
输出用户选择的某个工程师的底薪。
现在调整需求,在用户输入这 10 个 Java 工程师的底薪后,对他们的底薪进行加薪,加薪标准如下。

高薪人员(底薪大于等于 6000 元),加薪 5%。
非高薪人员,加薪 10%。 最后根据用户选择输出某个工程师加薪后的底薪。
新建一个 TestArray3.java 文件,接下来分步实现。

设计方法 inputEngSalary(int[] salary),作用是接收用户输入的薪资信息,并根据高薪还是低薪人员,计算出调薪后的薪资,存储到数组 salary 中,注意,我们暂且忽略调薪中出现的精度问题。

import java.util.Scanner;

class TestArray3 {
    static Scanner input = new Scanner(System.in);
    public static void inputEngSalary(int[] salary) {
        for (int i = 1; i <= 10; i++) {
            System.out.print("请输入第" + i + "工程师底薪:");
            salary[i - 1] = input.nextInt();
            if (salary[i - 1] >= 6000) {
                //高薪人员加薪5%
                salary[i - 1] = salary[i - 1] + (int) (salary[i - 1] * 0.05);
            } else {
                //非高薪人员加薪 10%
                salary[i - 1] = salary[i - 1] + (int) (salary[i - 1] * 0.1);
            }
        }
    }
}

假设调薪完成,数组中存储调薪后的薪资,根据用户输入查找第 index 个工程师的薪资的核心代码如下:

System.out.print("请输入你需要获取第几个工程师的底薪:");
int index = input.nextInt();//获取要查询的薪资的序号
System.out.println("第" + index + "个工程师的底薪为:" + basSalary[index - 1]);//注意第index个的下标是index-1

编写 main 方法实现需求,完整代码如下:

import java.util.Scanner;

class TestArray3 {

    static Scanner input = new Scanner(System.in);

    public static void main(String[] args) {
        //创建一个长度为10的整型数组,存放工程师底薪
        int[] basSalary = new int[10];
        //调用inputEngSalary方法输入工程师底薪并执行加薪操作
        inputEngSalary(basSalary);        //传递引用
        System.out.print("请输入你需要获取第几个工程师加薪后的底薪:");
        int index = input.nextInt();
        System.out.println("第" + index + "个工程师加薪后的底薪为:" + basSalary[index - 1]);
    }

    public static void inputEngSalary(int[] salary) {
        for (int i = 1; i <= 10; i++) {
            System.out.print("请输入第" + i + "工程师底薪:");
            salary[i - 1] = input.nextInt();
            if (salary[i - 1] >= 6000) {
                //高薪人员加薪5%
                salary[i - 1] = salary[i - 1] + (int) (salary[i - 1] * 0.05);
            } else {
                //非高薪人员计数10%
                salary[i - 1] = salary[i - 1] + (int) (salary[i - 1] * 0.1);
            }
        }
    }
}

编译运行此程序,结果如下图所示。

javac TestArray3.java
java TestArray3

图片描述

上面的程序中,main 方法中定义了一个数组 basSalary,并对其进行了赋值操作。main 方法在调用 inputEngSalary 方法的时候,将数组 basSalary 以参数的形式,传递给 inputEngSalary 方法,这就是所谓的引用传递。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值