Java——数组(概念理解+应用举例)

简介: Java——数组(概念理解+应用举例)

1.关于Java中的数组:  


Java语言中,数组是一个非常重要的概念,我们经常使用的数组,在这里和C语言基本上是一样的,无非是一维数组二维数组,那么对数组的初始化定义有两种方法,一个是静态初始化,另一个自然就是动态初始化

数组是一种数据结构,系统为数组分配的存储空间是连续的、指定长度的、且大小固定不变的,用来存储一组大小固定并且类型相同的数据。这些数据可以通过索引进行访问,数组的下标索引是从 0 开始,其取值范围必需是:0~数组长度-1 数组是JVM的核心类型,是 Java 语言的基元类型。数组类和数组实例的数据结构具有特殊性,由JVM 决定。运行时,数组越界的检查通过数组实例的 length 属性来完成,数组元素类型匹配的检查通过数组类中的元素类型属性来完成。

Java数组具有以下几个特点:

多维数组均是一维指针数组(数组实例)

Java 中的数组是静态数组,数组被创建后,其大小是不能改变的。

JVM扫描时产生数组类型(数组类型动态产生)。

数组越界,Java 中是运行时错误,产生异常(数组的 length 字段)。在 C 语言中是逻辑错误。而JVM在运行时判断,如果未越界则继续运行,如果越界则抛出异常。例如:数组越界、显式强类型转换等。

当然了,我们在使用Java数组的时候,难免的会出现一些错误问题,在处理这些问题的时候,一般是下面的步骤👇👇👇

存在的问题检测问题解决问题

1. 存在的问题:数组越界问题,数组元素类型匹配问题。(这两个相信大家在C语言的学习中,一定不陌生)

2. 检测问题:数组越界问题由JVM在运行时来检测,如果存在问题,则抛出异常。

                     数组元素类型匹配,值类型匹配错误是逻辑错误。

                     数组元素类型匹配,引用类型匹配错误是异常。

3. 解决问题:捕获异常,处理异常。

下面,我们来看一个例子:👇👇👇

public class Test {
  public static void main(String[] args) {
    int[] a= {4,5,6};//静态初始化
    a[0]=1234567890;//修改a[0]的内容
    System.out.println("int a[0]="+a[0]);//输出修改之后的a[0]
    try {
      int i=3;
                        //由于所创建的数组a中只有三个值,而数组下标从0开始,所以只有a[0],a[1]和a[2]
      a[i]=8;
                        //这里的a[3]显然会产生越界问题
    }
    catch (Exception e) {//在这里直接捕获,并处理异常
      System.out.println("数组越界异常!");
    }
  }
}

运行结果如下:

可以看到程序输出了上图的结果!!!

在这里,我们首先使用静态初始化来创建一个数组a,包含3个数,因为数组的下标是从0开始的,所以这三个数分别对应a[0]a[1]a[2],那么,我们修改a[0]是完全可以的。但是后面又企图对a[3]进行赋值,显然已经超出数组下标的最大范围,这里会产生越界问题,直接跳转到下面的catch语句来捕获并处理异常!!!


2.一维数组:


1. JVM 在运行一个方法之前,先扫描方法体,如果类对象不存在,则先创建该类对象。然后,单步解释执行 main()方法体内的代码。

2. 数组类对象非常特殊,是由 JVM 扫描时自动产生的。在扫描 main()方法体时, JVM 将首先在Java 方法区,建立int[ ]数组类对象、double[ ]数组类对象、char[ ]数组类对象、boolean[ ]数组类对象、String[ ]数组类对象。数组实例的数据结构具有特殊性,也由 JVM 决定。

3. 然后,单步解释执行 main()方法体内的代码。

例如:double[ ] b = new double[10]; 赋值语句

赋值号左边,首先在堆栈压栈一个变量b,该变量b的类型是一个double[ ]数组类型,是一个引用类型。

然后赋值号右边,生成double[ ]数组类型的一个数组实例。

最后赋值号,将生成的数组实例的引用赋予变量b,即变量b引用数组实例。

下面,我们来看一个例子!!!👇👇👇

import java.util.*;
public class Main
{
  public static void main(String[] args)
  {
    int[] a=new int[10];
    double[] b=new double[10];
    char[] c=new char[100];
    boolean[] d=new boolean[20];
    String[] s=new String[5];
    /*下面输出各数组的数组名,注意输出的内容 */ 
    System.out.println("输出数组对象*****************");
    System.out.println(a);// 输出整型数组对象的哈希玛(地址)   
    System.out.println(b);// 输出双精度浮点型数组对象的哈希玛(地址)   
    System.out.println(c);// 输出字符型数组中的内容   
    System.out.println(d);// 输出布尔型数组对象的哈希玛(地址)   
    System.out.println(s);// 输出字符串数组对象的哈希玛(地址)
    System.out.println("-------------------------"); 
    /*下面输出各数组中第一个元素的值,注意输出的内容 */ 
    System.out.println("输出数组对象的成员************");
    System.out.println(a[0]);   
    System.out.println(b[0]);   
    System.out.println(c[0]); 
    System.out.println(d[0]);
    System.out.println(s[0]);   
    System.out.println("-------------------------"); 
    /*下面输出各数组的长度 */ 
    System.out.println("输出数组对象的长度***********");
    System.out.println("a.length="+a.length);   
    System.out.println("b.length="+b.length);   
    System.out.println("c.length="+c.length);   
    System.out.println("d.length="+d.length);   
    System.out.println("s.length="+s.length);   
    System.out.println("-------------------------"); 
    //getClass()是Object的方法成员  
    //getSuperclass()、getName()是Class的方法成员
    System.out.println("输出数组类的超类和反射类***********");        
    System.out.println("int数组实例的类:"+a.getClass().getName());
    System.out.println("double数组实例的类:"+b.getClass().getName());
    System.out.println("char数组实例的类:"+c.getClass().getName());
    System.out.println("boolean数组实例的类:"+d.getClass().getName());
    System.out.println("String数组实例的类:"+s.getClass().getName());
    //输出类的超类Object
    System.out.println("int数组实例的类的父类:"+a.getClass().getSuperclass().getName());
    //输出类的反射类类Class
    System.out.println("int数组实例的类的反射类:"+a.getClass().getClass().getName());
    Class c1=a.getClass();
    Class c2=b.getClass();
    System.out.println("a、b相同的父类:"+(c1==c2));
    Class d1=a.getClass().getSuperclass();
    Class d2=b.getClass().getSuperclass();
    System.out.println("a、b相同的父类:"+(d1==d2));
  }
}

运行结果如下:

Java语言中,Object类是所有类的父类,在代码中,我们通过getClass()来获取当前类的对象,而getSuperclass()是获取父类的对象,后面的getName()则是获取对应的名称。

最后6行中,因为数组aint类型的,而数组bdouble类型的,所以它们通过getClass()获取当前类的对象并不是相同的,而通过getSuperclass()获取当前父类的对象是相同的,因为其父类都是Object

(这段代码的输出结果中,有哈希码、反射类这些知识,博主也还在学习的过程中,所以在这里先不谈这个)


3.初始化数组


public class Test {
  public static void main(String[] args) {
    int[] a= {5,7,20};//定义并初始化数组,使用静态初始化 
    int[] b=new int[4];//定义并初始化数组,使用动态初始化 
    for(int i=0;i<b.length;i++) {
      b[i]=i+1;
    } 
    //循环输出a数组的元素   
    System.out.println("数组a中的元素是:");
    for(int i=0;i<a.length;i++) {
      System.out.print(a[i]+" ");
    }
    System.out.println();
    //输出b数组的长度
    System.out.println("b数组的长度为:"+b.length);   
    System.out.println("数组b中的元素是:");
    //循环输出b数组的元素   
    for(int i=0;i<b.length;i++) {
      System.out.print(b[i]+" ");
    }
    System.out.println();
    //因为a是int[]类型,b也是int[]类型,所以可以将a的值赋给b。   
    //也就是让b引用指向a引用指向的数组
    b=a;
    //再次输出b数组的长度   
    System.out.println("b数组的长度为:"+b.length);
    //再次循环输出b数组的元素  
    for(int i=0;i<b.length;i++) {
      System.out.print(b[i]+" ");
    }
  }
}

运行结果如下:

代码中注释写的挺详细的,大家可以看一下,对比程序运行结果,理解一下Java初始化数组的这样一个过程!!!

下面,我们在初始化数组的过程中,如果想要遍历输出数组元素,有下面两种方法👇👇👇

for(int i=0;i<a.length;i++) {
    System.out.print(a[i]+" ");
}
for(int e:a) {
    System.out.print(e+" ");
}
public class Test {
  public static void main(String[] args) {
    int[] a=new int[5];//定义并初始化数组,使用动态初始化 
    for(int i=0;i<a.length;i++) {
      a[i]=i+1;
    }
    System.out.println("数组a中的元素是:");
    //使用foreach语句遍历输出a数组中的元素 
    for(int e:a) {
      System.out.print(e+" ");
    }
  }
}

运行结果如下:

4.二维数组


Java中的多维数组本质上是多维的指针数组,均由多个一维数组组成。 

Java的二维数组实际上是一维的指针数组。在Java中不存在矩阵数组。 

我们来看下面的例子!!!👇👇👇

public class Test {
  public static void main(String[] args) {
    int[][] a={ {1,2,3 },{4,5,6} };//二维数组静态初始化    
    System.out.println("数组a一维长度:"+a.length);   
    System.out.println("数组a二维长度:"+a[0].length);   
    System.out.println("数组a中的元素:");   
    //使用嵌套的for循环输出   
    for(int i=0;i<a.length;i++) {    
      for(int j=0;j<a[i].length;j++) {     
        System.out.print(a[i][j]+" ");    
      }    
      System.out.println();   
    }   
    System.out.println("-------------------------");    
    int[][] c=new int[3][4];//二维数组动态初始化,一维和二维都指定长度    
    //使用嵌套的for循环初始化二维数组  
    for(int i=0;i<c.length;i++) {    
      for(int j=0;j<c[i].length;j++) {     
        c[i][j]=i+j;    
      }   
    }   
    System.out.println("数组c中的元素:");
    //使用嵌套的for循环输出   
    for(int i=0;i<c.length;i++) {    
      for(int j=0;j<c[i].length;j++) {     
        System.out.print(c[i][j]+" ");
      }    
      System.out.println();   
    }   
    System.out.println("-------------------------"); 
    int[][] d=new int[2][];//声明二维数组时,只给出一维长度   
    //二维长度不等   
    d[0]=new int[3];   
    d[1]=new int[4];   
    //初始化   
    for(int i=0;i<d.length;i++) {    
      for(int j=0;j<d[i].length;j++) {     
        d[i][j]=i+j;    
      }   
    }   
    System.out.println("数组d中的元素:");   
    //使用嵌套的for循环输出   
    for(int i=0;i<d.length;i++) {    
      for(int j=0;j<d[i].length;j++) {     
        System.out.print(d[i][j]+" ");    
      }    
      System.out.println();   
    }   
    System.out.println("-------------------------"); 
    //数组类的超类和反射类   
    System.out.println("a数组实例的类:"+a.getClass().getName());   
    System.out.println("a[0]数组实例的类:"+a[0].getClass().getName());   
    System.out.println("a数组实例的类的父类:"+a.getClass().getSuperclass().getName());   
    System.out.println("a数组实例的类的反射类:"+a.getClass().getClass().getName());
    Class c1=a.getClass();   
    Class c2=d.getClass();   
    System.out.println("a、d相同的父类:"+(c1==c2));
  }
}

运行结果如下:

Java语言的二维数中,它的一维长度其实就是对应的二维数组的行数,而二维长度其实就是对应的二维数组的列数。而二维长度可以明确指定,也可以不指定,即二维长度不一定是相等的,也可能在第一行中是3列,在第二行中变成了4列。

在遍历输出二维数组的时候,要注意双重for循环👇👇👇

for(int i=0;i<a.length;i++) {//对应的是二维数组a的行数
    for(int j=0;j<a[i].length;j++) {//对应的是二维数组a的列数
  System.out.print(a[i][j]+" ");    
    }    
    System.out.println();   
}

在这里,我们仍然可以通过getClass().getSuperclass().getName()来获取其父类的名字,也就是Object类。

因为二维数组a和二维数组d都是int类型的,所以直接通过getClass()获取的当前类的对象就是相同的,即true

在看完了这篇博文之后,我们主要对Java数组有了一定的理解,包括:使用数组会产生的一些问题及解决方法,一维和二维数组的定义初始化、赋值以及遍历输出。

这就是博主总结的Java数组的相关内容,希望对你们有所帮助!!!欢迎大家留言评论!!!😀😀😀

相关文章
|
1天前
|
Java 测试技术
Java一分钟之-正则表达式在Java中的应用
【5月更文挑战第14天】正则表达式是Java中用于文本处理的强大力量,通过`java.util.regex`包支持。常见问题包括元字符的理解、边界匹配和贪婪/懒惰量词的使用。错误通常涉及未转义特殊字符、不完整模式或过度匹配。要避免这些问题,需学习实践、使用在线工具和测试调试。示例代码展示了如何验证邮箱地址。掌握正则表达式需要不断练习和调试。
14 2
|
1天前
|
搜索推荐 算法 Java
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
【5月更文挑战第4天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
10 0
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
|
1天前
|
存储 Java
滚雪球学Java(28):轻松掌握数组:访问和遍历技巧
【5月更文挑战第3天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
11 2
滚雪球学Java(28):轻松掌握数组:访问和遍历技巧
|
1天前
|
存储 Java ice
【Java开发指南 | 第十六篇】Java数组及Arrays类
【Java开发指南 | 第十六篇】Java数组及Arrays类
8 3
|
1天前
|
Java 编译器
【Java开发指南 | 第一篇】类、对象基础概念及Java特征
【Java开发指南 | 第一篇】类、对象基础概念及Java特征
9 4
|
1天前
|
Java 编译器 开发者
Java一分钟之-Java注解的理解与应用
【5月更文挑战第12天】本文介绍了Java注解的基础知识和常见应用,包括定义、应用和解析注解。注解在编译检查、框架集成和代码生成等方面发挥重要作用。文章讨论了两个易错点:混淆保留策略和注解参数类型限制,并提供了避免策略。提醒开发者避免过度使用注解,以保持代码清晰。理解并恰当使用注解能提升代码质量。
13 3
|
1天前
|
Java API 开发者
Java中Lambda表达式的深入理解与应用
【5月更文挑战第12天】在Java 8之后,Lambda表达式已经成为了Java开发者必备的技能之一。Lambda表达式以其简洁、灵活的特点,大大提高了编程的效率。本文将深入探讨Lambda表达式的基本概念,语法规则,以及在实际开发中的应用,帮助读者更好地理解和使用Lambda表达式。
|
1天前
|
存储 算法 搜索推荐
滚雪球学Java(27):从零开始学习数组:定义和初始化
【5月更文挑战第2天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
9 3
|
1天前
|
Java 索引
Java中数组详解
Java中数组详解
45 19
|
1天前
|
Java
解析java中的数组
解析java中的数组
13 3