【Java 基础语法】深度剖析 Java 中的数组(1)

简介: 一、数组基本用法1. 什么是数组和 C 语言一样,Java 中的数组是一块连续的内存,里面可以存放相同类型的变量。它可以在我们要创建若干相同类型变量时,实行批量创建。但是 Java 中的数组与 C 语言还是有蛮多不同的地方,接下来让我们先了解数组的创建!

一、数组基本用法

1. 什么是数组

和 C 语言一样,Java 中的数组是一块连续的内存,里面可以存放相同类型的变量。它可以在我们要创建若干相同类型变量时,实行批量创建。

但是 Java 中的数组与 C 语言还是有蛮多不同的地方,接下来让我们先了解数组的创建!

2. 创建数组

在 Java 中数组的创建有三种方式

  1. 静态初始化

    int[] array1 = {1,2,3,4,5};
  2. 动态初始化

    int[] array2 = new int[5];    // 默认元素为0
    // 打印结果为:[0, 0, 0, 0, 0]
  3. 动态初始化

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

注意事项

  • Java 中 [] 符号,可以写在变量名前面(写在后面也行)。而这样我们可以更好的理解,上述数组的类型是 int[]
  • 数组类型中的 [] 内不能写数值
  • 静态初始化的时候,数组元素个数和初始化数据的格式是一致的

3. 数组的使用

  1. 和 C 语言一样,Java 中访问数组的某个元素直接使用 [] 获取就行,如

    int[] array = {1, 2, 3};
    System.out.println(arrary[1]);
    // 打印结果为:2

    注意事项

    使用 [] 需要注意,下标范围为[0,length - 1]。如果越界将会出现以下异常 java.lang.ArrayIndexOutOfBoundsException
  2. 在 Java 中如果要遍历数组的话,有多种方法

    1. 法一(使用循环语句)

      int[] array = {1, 2, 3};
      for(int i = 0; i <array.length; i++){
          System.out.println(array[i]);
      }

      在 Java 中,如上述代码使用 数组对象.length 就可以得到该数组的长度

    2. 法二(使用增强 for 循环 for-each)

      int[] array = {1, 2, 3};
      for(int x : array){
          System.out.println(x);
      }

      如上述代码,该语句会便利数组 array,并且每次都会将数组的元素保存在变量 x 中

    3. 法三(使用 Arrays 类中的 toString 方法)

      // 使用 Arrays 类前先导入它的包
      import java.util.Arrays;
      public class TestDemo{
          public static void main(Strings[] args){
              int[] array = {1, 2, 3};
              String ret = Arrays.toString(array);
              System.out.println(ret);
          }
      }
      // 打印结果为:[1, 2, 3]

      Arrays 类 中 toString 的功能就是将当前的数组转换成字符串的形式返回,返回值就是字符串

    上述遍历方式各有各的特点,至于什么时候用哪一遍历方式,据情况而定

二、数组作为方法的参数

1. 认识 JVM 内存区域划分

我们知道,一个 Java 文件的执行需要先通过编译变成字节码文件,字节码文件再痛过 Java 虚拟机运行在这里插入图片描述

因为字节码文件是被 JVM 转换成平台所能执行的形式所运行的,那么 JVM 到底是怎样的呢?

JVM 本质其实就是一个用 C/C++ 代码实现的软件,它的内存被划分五块为如图所示的样子在这里插入图片描述

那么这里面的各块都分别有啥意义呢?

  • 程序计数器:是一个很小的空间,保存下一条执行的指令地址(通俗的来说就是你本来在敲代码,你老妈喊你去吃饭,但你吃完饭后还要回来执行完你没敲完的代码)在这里插入图片描述
  • Java 虚拟机栈:这就是我们平常说的栈,它重点是存储局部变量(像上面创建的数组 int[] array = {1, 2, 3} 的存储地址的引用就是保存在这里)
  • 本地方法栈:本地方法栈与虚拟机栈的作用类似,只不过保存的内容是 Native 方法的局部变量(在有些版本的 JVM 的实现中(例如 HotSpot),本地方法和虚拟机栈是一起的)
  • 堆:这就是我们平常说的堆,是 JVM 所管理的最大的内存区,使用 new 创建的对象都是在堆上保存(例如 int[] array = new int[]{1, 2, 3}
  • 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(方法编译出的字节码就是保存在这里)
  • 运行时常量池:这个是方法区的一部分(上述未画出),存放字面量(字符串常量)与符号引用(注意:从 JDK 1.8 开始,运行时常量池在堆上)

补充(Native 方法)

JVM 是一个基于 C++ 实现的程序,在 Java 程序执行过程中,本质上也需要调用 C++ 提供的一些函数和操作系统底层进行一些交互。因此在 Java 开发中也会调用到一些 C++ 实现的函数

既然知道了 JVM 的一些知识点,那么我们就可以对我们上述三种创建数组的代码做一个存储区域分析

int[] array1 = {1,2,3,4,5};
int[] array2 = new int[5];
int[] array3 = new int[]{1, 2, 3, 4, 5};

分析结果如图

在这里插入图片描述

  1. 我们知道,array1、array2、array3 是局部变量,所以它们会在栈上开辟一块内存。
  2. Java 中的数组都属于对象,而对象保存在堆中(对象就是一个实体,比如实际生活中的花草树木,或者上述代码中的 {1, 2, 3, 4, 5} 或者用更加规范的方式 new 出来的对象)
  3. 而保存在堆上的对象又有着自己的内存。上述三个局部变量又是引用变量(即这个变量里面存储的是一个地址),它们将会存储对应将每个对象的元素的首地址
  4. 按照术语来说,用array1举例就是:array1 就是一个引用,它引用了一个对象(指向一个对象)

2. 数组传参以及被调用的过程

我们直接通过一个图片来感受下面代码中数组传参以及被调用的过程

public static void main(String[] args){
    int[] array = {1, 2, 3};
    print(array;)
}
public static void print(int[] array){
    for(int x : array){
        System.out.print(x + " ");
    }
}
// 打印结果为:1 2 3

在这里插入图片描述

3. 理解引用类型

从上图我们可以知道,参数传数组类型,实参和形参其实都是引用,共同指向同一个对象。

因此如果形参将对象的值改变,那么实参的值也随即改变。可以用一个代码举例

public static void main(String[] args){
    int[] array = {10, 20};
    System.out.print("交换前:array[0] = " + array[0] + " array[1] =" + array[1]);
    System.out.println();
    swap(array);
    System.out.print("交换后:array[0] = " + array[0] + " array[1] =" + array[1]);
}
public static void print(int[] array){
    int tmp = array[0];
    array[0] = array[1];
    array[1] = tmp;
}
// 结果为: 
// 交换前:array[0] = 10 array[1] = 20;
// 交换后:array[0] = 20 array[1] = 10;

为了在理解上更加清晰,我们再举一个例子

public static void main(String[] args){
    int[] array1 = {1, 2, 3};
     int[] array2 = array1;  
}   

我们可以说 array2 这个引用指向 array1 这个引用吗?不能!这其实是表述有误!

引用不能说指向引用,引用只能说指向另一个引用所指的对象。故我们应该理解成:array2 这个引用指向了 array1 这个引用所指向的对象

小结

  • 引用类型本质上只是存了一个地址
  • Java 将数组设定成引用类型,这样后续进行数组参数传参,其实只是将数组的地址传到函数的形参中。这样可以避免对整个数组进行拷贝,减小开销
  • Java 中的引用类型有:String、数组、类、接口、枚举、抽象类

4. 认识 null

我们来看一个代码

int[] array = null;

上述代码的意思就是 array 这个引用不指向任何对象。这其实和 C 语言里的空指针类似,当我们不道该数组初始化为多少时,就可以赋值为 null

注意

  • null 在 Java 中表示空引用,是一个无效的引用。因此不能对这个内存进行任何读写操作,如果对上述代码进行打印的话,会出现一个 java.lang.NullPointerException 的异常
  • Java 中并没有约定 null 和 0 号地址的内存有任何联系(这和 C 语言中的指针赋值为 null 就是表示0号地址不同)

三、数组作为方法的返回值

在 C 语言中,数组是不能作为返回值的。但是在 Java中,数组可以作为返回值

public static void main(String[] args){
    int[] array = {1, 2, 3};
    int[] array1 = func(array);
}
public static int[] func(int[] array){
    int[] arr = new int[array.length];
    for(int i = 0; i < array.length; i++){
        arr[i] = 2 * array[i];
    }
    return arr;
}
// 上述代码就是创建一个新数组并且将原数组的值扩大一倍存入新数组中

如果大家有兴趣的话可以对上述代码里面的参数进行内存区域的分析,以加深对引用的理解!
注意

数组作为方法的返回值时,返回的是数组的首地址

四、总结

该章主要讲解了 Java 中数组的简单使用,以及作为引用类型传参且被调用时的一个分析。不过 Java 中的数组不仅仅如此,下章将介绍二维数组,并且通过多个数组习题让大家熟练数组的使用!
在这里插入图片描述

相关文章
|
10天前
|
IDE Oracle Java
java基础教程(1)-Java概述和相关名词解释
【4月更文挑战第1天】Java是1995年Sun Microsystems发布的高级编程语言,以其跨平台特性著名。它介于编译型和解释型语言之间,通过JVM实现“一次编写,到处运行”。Java有SE、EE和ME三个版本,分别针对标准、企业及嵌入式应用。JVM是Java虚拟机,确保代码在不同平台无需重编译。JRE是运行环境,而JDK包含开发工具。要安装Java开发环境,可从Oracle官网下载JDK,设置JAVA_HOME环境变量并添加到PATH。
|
2天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
3天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
5天前
|
Java 索引
Java基础教程(6)-Java中的流程控制语句
【4月更文挑战第6天】Java流程控制包括选择(if, switch)、重复(while, do-while, for)和跳转(break, continue, return)语句。选择语句根据条件执行不同路径,if和switch用于单条件和多条件分支。重复语句用于循环,如for循环的初始化、条件和迭代部分,以及while和do-while循环。跳转语句中,break用于立即退出循环,continue结束当前循环迭代,return则从方法中返回。此外,Java的for each循环简化了数组或集合的遍历,但不能控制遍历顺序或索引。
|
6天前
|
存储 Java 编译器
Java基础教程(4)-Java中的操作符
【4月更文挑战第4天】Java中的String是常用类,字符串是不可变对象,用双引号表示。String对象在编译期长度受限于65535,运行期不超过Int范围。字符串方法如length()、substring()、replace()、equals()等提供了多种操作。可变字符串可使用StringBuffer或StringBuilder。String对象通过字符串池优化内存,池中已有相同内容字符串则返回其引用。
|
7天前
|
存储 安全 Java
Java语法掌握:打好编程基础的关键(二)
Java语法掌握:打好编程基础的关键
41 0
|
7天前
|
存储 Java
Java语法掌握:打好编程基础的关键(一)
Java语法掌握:打好编程基础的关键
10 0
Java语法掌握:打好编程基础的关键(一)
|
21天前
|
Java
java 8 数组转字符串并以逗号分隔
java 8 数组转字符串并以逗号分隔
11 0
|
28天前
|
Java
【Java】数组中的拷贝方法与初步理解深浅拷贝
【Java】数组中的拷贝方法与初步理解深浅拷贝
12 0
|
28天前
|
存储 Java C语言
【Java】以数组为例简单理解引用类型变量
【Java】以数组为例简单理解引用类型变量
14 1