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行中,因为数组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初始化数组的这样一个过程!!!
下面,我们在初始化数组的过程中,如果想要遍历输出数组元素,有下面两种方法👇👇👇
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数组的相关内容,希望对你们有所帮助!!!欢迎大家留言评论!!!😀😀😀