继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【Java核心技术卷】深入理解Java数组

沉晓Jeffery
关注TA
已关注
手记 31
粉丝 12
获赞 52

数组介绍:

数组是一种数据结构,系统为数组分配的存储空间是连续的、指定长度的且大小固定不变的,用来存储一组大小固定并且类型相同的数据。
这些数据可以通过索引进行访问,数组的下标索引是从0开始,其取值范围必需是:0 ~ 数组长度length – 1 。

Java数组的特点:

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

这里以三维数组为例

int[][][] T = new int[2][2][2];

值得注意的是 在Java中没有矩阵数组,全部都是引用数组,没有选择的余地,但是矩阵数组操作效率比较高

2.Java中的数组是静态数组,数组被创建后,其大小是不能改变的。
3.由JVM扫描时产生数组类型(数组类型动态产生)
4.数组越界,在Java中是运行时错误,产生异常(数组的length字段)
;在C语言中是逻辑错误。JVM在运行时判断,如果未越界则继续运行,如果越界则抛出异常。例如:数组越界、显式强类型转换等。int[] a = new int[10];
int[] a = new int[10];
int i = 20;
a[i] = 8;
运行时为:
int[] a = new int[10];
int i = 20;
if i<a.length 
a[i] = 8;
else
throw 数组越界异常对象

注意以上加粗代码的意思是JVM会进行添加的,是JVM帮的忙

如果你不了解JVM,那很难达到比较高的境界

下面有对数组存在的问题的介绍

5.参考C语言:

C语言中矩阵数组与指针数组的选择能力(数据结构的选择能力)
1)运行效率
运行效率 = 1次 X 生成时间 + n次 X 操作时间
2)产生的垃圾
3)数据结构的大小\
6.对象实例由对象头、实例数据组成,其中对象头包括markword和类型指针,如果是数组,还包括数组长度;
 | 类型     | 32位JVM | 64位JVM   |
 | markword | 32bit    | 64bit      |
 | 类型指针  | 32bit    | 64bit ,开启指针压缩时为32bit |
 | 数组长度  | 32bit    | 32bit      |

Java数组存在的问题

(存在的)问题---〉检测(问题)---〉解决(问题)

Java数组:
1)(存在的)问题
    a)    数组越界问题
    b)    数组元素类型匹配问题
2)检测(问题)
数组越界问题由JVM在运行时来检测,如果存在问题,则抛出异常
数组元素类型匹配,值类型匹配错误是逻辑错误
数组元素类型匹配,引用类型匹配错误是异常
3)解决(问题)
捕获异常,处理异常

public class Test
{
     public static void main(String[] arg)
     {
        float[] a = {1,2,3};
        a[0] = 123456789;
        System.out.println("float a[0] =" + a[0] + ",int x=" + 123456789);

        try{
            int i = 3;
            a[i] = 8;
        }
        catch(Exception e){
            System.out.println("数组越界异常!");
        }
    }
}


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


一维数组

创建一维数组:

//*****程序代码:ArrayDemo1.java *******public class ArrayDemo1 {	public static void main(String args[]) {		// 声明一个整型数组a
		int[] a;		// 给数组a分配存储空间:10*4个字节
		a = new int[10];		// 定义一个长度为10的双精度浮点型数组,10*8个字节
		double[] b = new double[10];		// 定义一个长度为100的字符型数组c,100*2个字节
		char[] c = new char[100];		// 定义一个长度为20的布尔型数组,20*1个字节
		//java规范中,没有明确指出boolean的大小。
        //在《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,
        //具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。
        //boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位
		boolean[] d = new boolean[20];		//定义一个长度为5的字符串数组
		String[] s=new String[5];		/* 下面输出各数组的数组名,注意输出的内容 */
		//在需要出现String类型的地方,出现了引用,
        //则编译器生成的字节码a.toString()
		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("-------------------------");

		System.out.println("输出数组类的超类和反射类*");		// getClass()是Object的方法成员
		// getSuperclass()、getName()是Class的方法成员
        // 输出类   int[]		
        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());
      	System.out.println("int数组实例的类:" + a.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));	//false
	}
}

运行结果:

http://img.mukewang.com/5dc7a7b70001acf706090403.jpg
1)JVM在运行一个方法之前,先扫描方法体,如果类对象不存在,则先创建该类对象。然后,单步解释执行main()方法体内的代码。
2)数组类对象非常特殊,是由JVM扫描时自动产生的。在扫描main()方法体时,JVM将首先在Java方法区,建立int[]数组类对象、double[]数组类对象、char[]数组类对象、boolean[]数组类对象、String[]数组类对象。
3)然后,单步解释执行main()方法体内的代码。
例如:double[] b = new double[10]; 赋值语句
1)赋值号左边,首先在堆栈压栈一个变量b,该变量b的类型是一个double[]数组类型,是一个引用类型。
2)然后赋值号右边,生成double[]数组类型的一个数组实例。
3)最后赋值号,将生成的数组实例的引用赋予变量b,即变量b引用数组实例。

http://img3.mukewang.com/5dc7a7b80001ee6311931080.jpg

初始化数组:

// *********程序代码:ArrayDemo2.java**********public class ArrayDemo2 {	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, len = a.length; i < len; 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, len = b.length; i < len; 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);
	}
}

1)JVM在运行一个方法之前,先扫描方法体,如果类对象不存在,则先创建该类对象。然后,单步解释执行main()方法体内的代码。
2)数组类对象非常特殊,是由JVM扫描时自动产生的。在扫描main()方法体时,JVM将首先在Java方法区,建立int[]数组类对象。
3)然后,单步解释执行main()方法体内的代码。
例如:int[] a = { 5, 7, 20 };赋值语句
1)赋值号左边,首先在堆栈压栈一个变量a,该变量a的类型是一个int[]数组类型,是一个引用类型。
2)然后赋值号右边,使用静态初始化语法,生成int[]数组类型的一个数组实例。
3)最后赋值号,将生成的数组实例的引用赋予变量a,即变量a引用数组实例。

http://img4.mukewang.com/5dc7a7b80001783411930589.jpg

运行结果:

http://img4.mukewang.com/5dc7a7b90001533606050204.jpg


foreach遍历数组

for(数据类型 变量名:数组名)
foreach语句中变量的数据类型必须与数组元素或集合的数据类型一致。
使用foreach遍历数组,无需获得数组或集合的长度,也无需根据索引来访问数组元素或集合元素,foreach循环自动遍历数组或集合的每个元素。

// *****程序代码:ForeachDemo.java*****public class ForeachDemo {	public static void main(String[] args) {		// 定义并初始化数组,使用静态初始化
		int[] a = { 5, 7, 20 };		// 使用foreach语句遍历输出a数组中的元素
		System.out.println("数组a中的元素是:");		for (int e : a) {
			System.out.println(e);
		}
	}

}

运行结果:

http://img1.mukewang.com/5dc7a7b9000111aa06080205.jpg

二维数组

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

// ***程序代码:Array2DDemo.java****public class Array2DDemo {	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));	//true
	}
}// Java中的多维数组本质上是多维的指针数组,均由多个一维数组组成。


运行结果:

http://img4.mukewang.com/5dc7a7b900013fb506000521.jpg

内存逻辑图

http://img2.mukewang.com/5dc7a7ba00011f3a12311428.jpg



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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP