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("数组越界异常!");
		}
	}
}

运行结果如下: 

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

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

在这里,我们首先使用静态初始化来创建一个数组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——数组(概念理解+应用举例)_数组_02

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

最后6行中,因为数组a是int类型的,而数组b是double类型的,所以它们通过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——数组(概念理解+应用举例)_数组_03

代码中注释写的挺详细的,大家可以看一下,对比程序运行结果,理解一下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+" ");
		}
	}
}

运行结果如下: 

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

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——数组(概念理解+应用举例)_数组_05

在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数组的相关内容,希望对你们有所帮助!!!欢迎大家留言评论!!!😀😀😀